【upc】西⽐拉先知系统 | 无所不能的分块!

问题 B: 西⽐拉先知系统

时间限制: 2 Sec  内存限制: 128 MB
提交 状态

题目描述

西⽐拉先知系统是⼀个强⼤的⼼灵指数监测⽹絡,能以声像扫描主动监控市⺠的⼼智与精神状态。为了判定出更复杂的⼈类⼼理参数,西⽐拉系统纳⼊了不同于既存⼈类规范的超群⼈格──不会随意和他⼈产⽣共鸣,也不会感情⽤事,能以⾮⼈类的眼光来俯瞰并裁定⼈类。
被纳⼊的超群⼈格会相互影响,共同处理数据。他们之间具体的影响⽅式形如⼀张⽆向图,如果你对⼀个节点进⾏操作,和这个节点相邻的节点也会受到相同的影响。
操作有⼀种:使⼀个节点的权值加上。
同时你还希望询问⼀个节点的权值(每⼀个节点的初始权值为0)。

输入

第⼀⾏读⼊n,m,Q,表⽰节点个数和边数,以及操作和询问的总数。
接下来m⾏,每⾏两个数ui,vi表⽰ui,vi之间有连边。
接下来Q,每⾏先读⼊⼀个type
type=0表⽰⼀个询问,读⼊⼀个x,表⽰询问x节点的权值。
type=1表⽰⼀个操作,读⼊x,y,表⽰将x节点的权值加上y。(与x相邻的节点权值也要加上y)

输出

对于每⼀个询问输出⼀⾏,表⽰该节点的权值。

样例输入 Copy

4 4 4
1 2
1 3
1 4
2 3
1 1 1
0 2
1 3 3
0 2

样例输出 Copy

1
4

提示

n,m,Q≤3×105,y≤1000


题目大意:

中文题意

题目思路:

看看看看到这个题...乐巨说说说说说说说她也喜欢..乐巨

但是有点难搞,往往题意简单的题目,思路就偏古怪

这题和之前cf上一道题非常的相似!

(题号评论点赞即可得到—————哈哈哈哈哈哈哈啊哈)

下面正题,考虑每次修改绝对不可能是通过邻接表遍历的

菊花图中间一个点修改10000次了解下?

所以应该寻找别的方法去解决这个问题...But好像都没用?

所以试一下最后的方法吧——分块

用分块之前必须要考虑一下复杂度的问题:n = 3e5

= sqrt(m)*p = 550*300000 = 165000000

1s在没有任何常数掺杂的情况下是可以到1e8的,题限给了2s

那就试试了,之后就绿了

说一下如何分块,考虑每次修改的时候极端情况是作为菊花图时,对每条邻接边都要修改,所以复杂度太高了

考虑将每个点的邻边分块,也就是说,若x有y个邻接点,将y个邻接点分为y/block个块

最后计算 被块影响的和 + 被单点影响的和 即为答案 | 这个输出是O1的

最后附带一个复杂度的问题,或许有小伙伴考虑到有可能一个点的块数太多容易超时,其实不会的

若令 block = sqrt(n),所以假设一个点与其他n-1个点相邻,也最多被分为sqrt(n)块

所以整体复杂度:= sqrt(m)*p = 550*300000 = 165000000

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(3)
#include 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair pp;
const ll INF=1e17;
const int Maxn=1e6+10;
const int maxn =1e6+10;
const int mod= 1e9+7;
const int Mod = 1e6+7;
const int S = 1000;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
vectorv[maxn];
vectorb[maxn],g[maxn];
ll c[maxn];
int sz[maxn];
int main()
{
 
    read(n);read(m);read(p);
    int block = sqrt(m);
    for(int i=1;i<=m;i++){
        int x,y;scanf("%d%d",&x,&y);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    int cnt = n+1;///block number
    for(int i=1;i<=n;i++){
        sz[i] =v[i].size();
        if(sz[i]>=block){
            int temp = 0;
            for(int k=0;k

 

你可能感兴趣的:(upc经典题目及题解整理,分块)