【BZOJ3730: 震波】套路动态点分治+树状数组
学了有这么久的动态点分治了,突然发现博客里没有相关文章,补上一发。
BZOJ3730
3730: 震波
Time Limit: 15 Sec Memory Limit: 256 MB Submit: 4108 Solved: 721 [Submit][Status][Discuss]Description
在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
为了体现程序的在线性,操作中的x、y、k都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为0。
Input
第一行包含两个正整数N和M。
第二行包含N个正整数,第i个数表示value[i]。
接下来N-1行,每行包含两个正整数u、v,表示u和v之间有一条无向边。
接下来M行,每行包含三个数,表示M次操作。
Output
包含若干行,对于每个询问输出一行一个正整数表示答案。
Sample Input
8 1
1 10 100 1000 10000 100000 1000000 10000000
1 2
1 3
2 4
2 5
3 6
3 7
3 8
0 3 1
Sample Output
11100101
HINT
1<=N,M<=100000
1<=u,v,x<=N
1<=value[i],y<=10000
0<=k<=N-1
方法十分地套路(最近遇到的题目大都是这样,这也是常见的套路),动态点分治建立数据结构的时候,建立一个数据结构维护以自己为根的整颗分治理子树到自己的信息,然后再建一个数据结构维护以自己为根的整颗子树到分治父亲的信息。因为动态点分治里面经常会遇见要求从哪里到哪里的路径,这时候直接考虑父亲会算重,再减去在自己的子树里的相关信息就可以了。
这道题也一样,对于查询一个距离内的前缀和,平衡树、线段树、树状数组都是可以办到的,建点分树的时候,把所有距离插进数据结构,查询和修改都是跳跳点分树就好了。
这里写的树状树组:
#include<stdio.h> #include<iostream> #include<cstdio> #include<algorithm> #include<cstdio> #include<cstring> #include<vector> #define lowbit(x) ((x)&(-x)) using namespace std; const int maxn = 200005; int n,m; struct btr{ vector<int>bit; int sz; void init(int s) { bit.resize(s+2); sz = s+1; } void add(int x,int d) { x+=1; for(;x<=sz;x+=lowbit(x)) bit[x]+=d; } int gsum(int x) { x+=1; x = min(sz,x); if(x<=0) return 0; int sm=0; for(;x;x-=lowbit(x)) sm+=bit[x]; return sm; } }treet[maxn],sont[maxn]; int en[maxn],la[maxn],nt[maxn],owo,val[maxn]; void adg(int x,int y) { en[++owo]=y; nt[owo]=la[x]; la[x]=owo; } vector<int>ve[maxn]; int rtsz,sm,rt; int sz[maxn]; bool vis[maxn]; void gsi(int x,int ba) { sz[x]=1; for(int it=la[x];it;it=nt[it]) { int y = en[it]; if(y==ba||vis[y]) continue; gsi(y,x); sz[x]+=sz[y]; } } int grt(int x,int ba) { int sso = 0; for(int it=la[x];it;it=nt[it]) { int y = en[it]; if(y==ba||vis[y]) continue; grt(y,x); sso = max(sso,sz[y]); } sso = max(sso,sm-sz[x]); if(sso<rtsz) rtsz=sso,rt=x; } int getrt(int x) { gsi(x,0); sm=sz[x]; rtsz=0x3f3f3f3f; grt(x,0); return rt; } int sta[maxn],stac[maxn],sso[maxn],fa[maxn],tp,MX,MMX; int dep[maxn],dis[20][maxn]; void getdis(int x,int ba,int dd,int ac,int dp) { sta[++tp] = dd; stac[tp]=ac; sso[tp]=val[x]; dis[dp][x] = dd; MX = max(MX,dd); MMX= max(MMX,dd); for(int it=la[x];it;it=nt[it]) { int y = en[it]; if(vis[y]||y==ba) continue; getdis(y,x,dd+1,ac,dp); } } void DC(int x) { vector<int>bc; vis[x] = 1; tp = 0; MMX = 0; for(int it=la[x];it;it=nt[it]) { int y = en[it]; if(vis[y]) continue; int p = getrt(y); MX=0; getdis(y,x,1,p,dep[x]); sont[p].init(MX); bc.push_back(p); } treet[x].init(MMX); treet[x].add(0,val[x]); for(int i=1;i<=tp;i++) { treet[x].add(sta[i],sso[i]); sont[stac[i]].add(sta[i],sso[i]); } int ss = bc.size(); for(int i=0;i<ss;i++) { int y = bc[i]; fa[y]=x; dep[y]=dep[x]+1; DC(y); } } int FRT; int query(int x,int k) { int ans = treet[x].gsum(k); for(int p=x;fa[p];p=fa[p]) { int dd = dis[dep[fa[p]]][x]; if(k>=dd) ans += treet[fa[p]].gsum(k-dd),ans -= sont[p].gsum(k-dd); } return ans; } void change(int x,int k) { treet[x].add(0,k-val[x]); for(int p=x;fa[p];p=fa[p]) { int dd = dis[dep[fa[p]]][x]; treet[fa[p]].add(dd,k-val[x]); sont[p].add(dd,k-val[x]); } val[x] = k; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&val[i]); } for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); adg(x,y); adg(y,x); } FRT = getrt(1); DC(FRT); int lastans = 0; int ty,x,y; for(int i=1;i<=m;i++) { scanf("%d%d%d",&ty,&x,&y); x^=lastans; y^=lastans; if(ty==0) { lastans = query(x,y); printf("%d\n",query(x,y)); } else { change(x,y); } } }