bzoj3730 [震波][动态树分治+线段树+LCA]
震波
Time Limit: 15 Sec Memory Limit: 256 MBSubmit: 1573 Solved: 358
[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
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
Source
题解:先建立点分树
ra :表示该节点点分树子树内到其距离为某值的所有节点的权值和
rb:示该节点点分树子树内到其父亲节点距离为某值的所有节点的权值和
另一个问题:如何快速求出两点间距离?使用RMQLCA,预处理后 O(1) 查询LCA深度即可。
然后就是类似是容斥吧,维护即可。
修改的话就是计算delta,来解决。
每次不管怎么样,log层,每层的线段树上解决,
n log n是极限,所以可以认为是 n log^2n的时间复杂度。
然后就可以解决了,线段树的基本操作吧。
1 #include<cstring> 2 #include<cmath> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdio> 6 7 #define N 100007 8 using namespace std; 9 inline int read() 10 { 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();} 13 while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 17 int n,m,lastans,S,tot,xj; 18 int cnt,hed[N],rea[N*2],nxt[N*2]; 19 int pos[N],mn[20][N*2],dep[N]; 20 int value[N],vis[N],sz[N],fa[N],ra[N],rb[N],rt,f[N],Log[N*2]; 21 int ls[N*200],rs[N*200],sum[N*200],tp; 22 23 void add(int u,int v) 24 { 25 nxt[++cnt]=hed[u]; 26 hed[u]=cnt; 27 rea[cnt]=v; 28 } 29 void get_root(int u,int fa) 30 { 31 sz[u]=1,f[u]=0; 32 for (int i=hed[u];i!=-1;i=nxt[i]) 33 { 34 int v=rea[i]; 35 if (vis[v]||v==fa)continue; 36 get_root(v,u),sz[u]+=sz[v],f[u]=max(f[u],sz[v]); 37 } 38 f[u]=max(f[u],S-sz[u]); 39 if (f[u]<f[rt])rt=u; 40 } 41 inline int dis(int x,int y) 42 { 43 int t=dep[x]+dep[y],k; 44 x=pos[x],y=pos[y]; 45 if (x>y)swap(x,y); 46 k=Log[y-x+1]; 47 return t-(min(mn[k][x],mn[k][y-(1<<k)+1])<<1); 48 } 49 void update(int p,int a,int l,int r,int &x) 50 { 51 if (!x)x=++xj; 52 sum[x]+=a; 53 if (l==r)return; 54 int mid=(l+r)>>1; 55 if (p<=mid)update(p,a,l,mid,ls[x]); 56 else update(p,a,mid+1,r,rs[x]); 57 } 58 int query(int p,int l,int r,int x) 59 { 60 if (!x) return 0; 61 if (l==r) return sum[x]; 62 int mid=(l+r)>>1; 63 if (p<=mid)return query(p,l,mid,ls[x]); 64 else return query(p,mid+1,r,rs[x])+sum[ls[x]]; 65 } 66 void calc(int u,int par,int p) 67 { 68 update(dis(u,p),value[u],0,n-1,ra[p]); 69 if (fa[p])update(dis(u,fa[p]),value[u],0,n-1,rb[p]); 70 for (int i=hed[u];i!=-1;i=nxt[i]) 71 { 72 int v=rea[i]; 73 if (vis[v]||v==par) continue; 74 calc(v,u,p); 75 } 76 } 77 void divide(int u) 78 { 79 calc(u,0,u),vis[u]=1;int yS=S; 80 for (int i=hed[u];i!=-1;i=nxt[i]) 81 { 82 int v=rea[i]; 83 if (vis[v])continue; 84 rt=0; 85 if (sz[v]>sz[u])S=yS-sz[u]; 86 else S=sz[v]; 87 get_root(v,0),fa[rt]=u; 88 divide(rt); 89 } 90 } 91 inline void modify(int x,int y) 92 { 93 for (int i=x;i!=0;i=fa[i]) 94 { 95 update(dis(x,i),y-value[x],0,n-1,ra[i]); 96 if (fa[i])update(dis(x,fa[i]),y-value[x],0,n-1,rb[i]); 97 } 98 value[x]=y; 99 } 100 inline int solve(int x,int p) 101 { 102 int res=0; 103 for (int i=x;i!=0;i=fa[i]) 104 { 105 if (dis(x,i)<=p)res+=query(p-dis(x,i),0,n-1,ra[i]); 106 if (fa[i]&&dis(x,fa[i])<=p)res-=query(p-dis(x,fa[i]),0,n-1,rb[i]); 107 } 108 return res; 109 } 110 void dfs(int u,int par) 111 { 112 pos[u]=++tot,mn[0][tot]=dep[u]; 113 for (int i=hed[u];i!=-1;i=nxt[i]) 114 { 115 int v=rea[i]; 116 if (v==par) continue; 117 dep[v]=dep[u]+1,dfs(v,u),mn[0][++tot]=dep[u]; 118 } 119 } 120 int main() 121 { 122 memset(hed,-1,sizeof(hed)); 123 124 n=read(),m=read(); 125 for (int i=1;i<=n;i++) 126 value[i]=read(); 127 for (int i=1;i<n;i++) 128 { 129 int x=read(),y=read(); 130 add(x,y),add(y,x); 131 } 132 dfs(1,0); 133 for (int i=2;i<=tot;i++)Log[i]=Log[i>>1]+1; 134 for (int i=1;(1<<i)<=tot;i++) 135 for (int j=1;j<=tot-(1<<i)+1;j++) 136 mn[i][j]=min(mn[i-1][j],mn[i-1][j+(1<<(i-1))]); 137 f[0]=1<<30,S=n; 138 get_root(1,0),divide(rt); 139 while(m--) 140 { 141 int flag=read(),x=read()^lastans,y=read()^lastans; 142 if (flag)modify(x,y); 143 else printf("%d\n",lastans=solve(x,y)); 144 } 145 }