题解:P11287 [COTS 2017] 影响 Utjecaj

· · 题解

思路:

注:分析默认 nmq 同阶。

假设从图中删去关键节点,那么图将被划分成若干个联通块。如果有关键点与联通块相连,那么这个联通块内的点都是可达的。

所以考虑将联通块打包,缩成一个点,断开关键节点之间的边。

那么一个点的影响力就是所有与之直接相连的点和自身的权值之和。

那么问题转化为了:

  1. 对点 x 和直接相连的点加上一个值。
  2. 查询点 x 和直接相连的点的权值和。

直接做是 O(n\sum deg_i)deg_i 是点 i 的出度。

考虑根号分治。我们设立一个阈值 B,初始时先将点 x 和直接相连的点的权值和预处理出来。对于修改操作,若 deg_x\le B,直接暴力修改,反之,我们对 x 打上标记。询问时,我们再在权值和的基础加上与 x 相连的且出度 >B 的点上的标记。修改操作是 O(B),而对于询问,默认 \sum deg_i \le 2\times n,那么出度 > B 的点不超过 {n}\over B,询问复杂度为 O({n\over B})

## code ```cpp #include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define mset(x,y) memset((x),(y),sizeof((x))) #define mcpy(x,y) memcpy((x),(y),sizeof((y))) #define FileIn(x) freopen(""#x".in","r",stdin) #define FileOut(x) freopen(""#x".out","w",stdout) #define debug(x) cerr<<""#x" = "<<(x)<<'\n' #define Assert(x) if(!(x)) cerr<<"Failed: "#x" at line "<<__LINE__,exit(1) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef __int128 Int; const int N=2e5+10,B=400; bool StM; int c[N],a[N],n,m,k,q; int in[N],Be[N]; ll b[N],sum[N],tag[N]; vector<int>G[N],E[N],H[N],Fa[N]; map<int,bool>Cenect[N]; map<pair<int,int>,bool>edge; void dfs(int now) { Be[now]=k,b[k]+=a[now]; for(int to:E[now]) if(!Be[to]) dfs(to); return; } void Main() { cin>>n>>m; for(int i=1;i<=n;i++) cin>>c[i]; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1,x,y;i<=m;i++) { cin>>x>>y; if(x>y) swap(x,y); if(edge.count({x,y})) continue; edge[{x,y}]=1; G[x].push_back(y); G[y].push_back(x); if(c[x]|c[y]) continue; E[x].push_back(y); E[y].push_back(x); } for(int i=1;i<=n;i++) if(!Be[i]) ++k,dfs(i); for(int now=1;now<=n;now++) { if(c[now]){ for(int to:G[now]) if(Be[to]^Be[now]&&!c[to]) { if(Cenect[Be[now]].count(Be[to])) continue; H[Be[now]].push_back(Be[to]),++in[Be[to]]; Cenect[Be[now]][Be[to]]=1; } } else{ for(int to:G[now]) if(Be[to]^Be[now]) { if(Cenect[Be[now]].count(Be[to])) continue; H[Be[now]].push_back(Be[to]),++in[Be[to]]; Cenect[Be[now]][Be[to]]=1; } } } for(int now=1;now<=k;now++) { sum[now]=b[now]; for(int to:H[now]) sum[now]+=b[to]; if(in[now]>B) for(int to:H[now]) Fa[to].push_back(now); } cin>>q; int op,x,y,now; while(q--) { cin>>op>>x; if(op==1){ cin>>y;now=Be[x]; int val=y-a[x]; a[x]=y,b[now]+=val,sum[now]+=val; if(in[now]>B) tag[now]+=val; else for(int to:H[now]) sum[to]+=val; } else{ ll delta=0;now=Be[x]; for(int to:Fa[now]) delta+=tag[to]; cout<<sum[now]+delta<<'\n'; } } } bool EdM; int main() { cerr<<fabs(&StM-&EdM)/1024.0/1024.0<<" MB\n"; ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int StT=clock(); int T=1; while(T--) Main(); int EdT=clock(); cerr<<1e3*(EdT-StT)/CLOCKS_PER_SEC<<" ms\n"; return 0; } ```