bzoj 4372 烁烁的游戏——动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372
和 bzoj 3070 震波 是一个套路。注意区间修改的话,树状数组不能表示 dis = 0 的位置,所以要手动改父亲的点权数组。
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define ll long long using namespace std; const int N=1e5+5,K=20; int n,w[N],hd[N],xnt,to[N<<1],nxt[N<<1],siz[N],rt,mn; int pre[N][K],dep[N],dis[N][K],fs[N],gs[N]; vector<ll> f[N],g[N]; bool vis[N]; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } int Mx(int a,int b){return a>b?a:b;} int Mn(int a,int b){return a<b?a:b;} void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;} void add(int cr,int x,int k){for(x=Mn(x,fs[cr]);x;x-=(x&-x))f[cr][x]+=k;} ll qry(int cr,int x){ll ret=0;for(;x&&x<=fs[cr];x+=(x&-x))ret+=f[cr][x];return ret;} void addx(int cr,int x,int k){for(x=Mn(x,gs[cr]);x;x-=(x&-x))g[cr][x]+=k;} ll qryx(int cr,int x){ll ret=0;for(;x&&x<=gs[cr];x+=(x&-x))ret+=g[cr][x];return ret;} void getrt(int cr,int fa,int s) { siz[cr]=1;int mx=0; for(int i=hd[cr],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=fa) { getrt(v,cr,s);siz[cr]+=siz[v];mx=Mx(mx,siz[v]); } mx=Mx(mx,s-siz[cr]); if(mx<mn)mn=mx,rt=cr; } void dfs(int cr,int fa,int ds) { pre[cr][++dep[cr]]=rt;dis[cr][dep[cr]]=ds; for(int i=hd[cr],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=fa)dfs(v,cr,ds+1); } void init(int cr,int s) { vis[cr]=1;fs[cr]=mn;gs[cr]=(mn<<1)+1; f[cr].resize(fs[cr]+1);g[cr].resize(gs[cr]+1); dfs(cr,0,0); for(int i=hd[cr],v;i;i=nxt[i]) if(!vis[v=to[i]]) { int ts=(siz[v]<siz[cr]?siz[v]:s-siz[cr]); mn=N;getrt(v,cr,ts);init(rt,ts); } } void mdfy(int cr,int d,int k) { add(cr,d,k); w[cr]+=k; for(int i=dep[cr]-1;i;i--) { if(dis[cr][i]>d)continue; add(pre[cr][i],d-dis[cr][i],k); w[pre[cr][i]]+=k;///// addx(pre[cr][i+1],d-dis[cr][i],k); } } ll query(int cr) { ll ret=w[cr]; for(int i=dep[cr]-1;i;i--) { ret+=qry(pre[cr][i],dis[cr][i]); ret-=qryx(pre[cr][i+1],dis[cr][i]); } return ret; } int main() { n=rdn(); int Q=rdn(); for(int i=1,u,v;i<n;i++) u=rdn(),v=rdn(),add(u,v),add(v,u); mn=N;getrt(1,0,n);init(rt,n); int x,d,k;char ch[5]; while(Q--) { scanf("%s",ch);x=rdn(); if(ch[0]=='Q')printf("%lld\n",query(x)); else { d=rdn(); k=rdn(); mdfy(x,d,k); } } return 0; }