时间限制: 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
1s在没有任何常数掺杂的情况下是可以到1e8的,题限给了2s
那就试试了,之后就绿了
说一下如何分块,考虑每次修改的时候极端情况是作为菊花图时,对每条邻接边都要修改,所以复杂度太高了
考虑将每个点的邻边分块,也就是说,若x有y个邻接点,将y个邻接点分为y/block个块
最后计算 被块影响的和 + 被单点影响的和 即为答案 | 这个输出是O1的
最后附带一个复杂度的问题,或许有小伙伴考虑到有可能一个点的块数太多容易超时,其实不会的
若令 block = sqrt(n),所以假设一个点与其他n-1个点相邻,也最多被分为sqrt(n)块
所以整体复杂度:
/*** 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