BZOJ 3730 震波
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
先构造出一个动态点分树
查询时,首先就考虑在当前块内和x距离为k的
然后还要考虑其他含有x的树根,所以顺着点分树
然后向上走到i,距离为d
查询距离树根为k-d的点权和
这些用线段树以距离为下标实现,每一个根动态开点
但是还要减去原来子树的,因为不可能走重复的路径
所以再维护一颗线段树,在往上跳时记录x传递到x上一个根的答案
查询时减去x传递到上一根的答案就行了
此题玄学卡常,可以换一种点分写法,这样可以省去get_size操作,快了不少
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 #define MAX 120000 8 struct Node 9 { 10 int next,to; 11 }edge[MAX<<1]; 12 int num,head[MAX]; 13 int dep[MAX],fa[MAX],pos,size[MAX],minsize,root; 14 int FA[MAX],son[MAX],top[MAX],Size; 15 int sum[MAX*150]; 16 int ch[MAX*150][2],RT[MAX<<1],n,m; 17 int ans,val[MAX]; 18 bool vis[MAX]; 19 inline int gi() 20 { 21 int x=0,flag=1; 22 char ch=getchar(); 23 while (ch<'0'||ch>'9') 24 { 25 if (ch=='-') flag=-1; 26 ch=getchar(); 27 } 28 while (ch>='0'&&ch<='9') 29 { 30 x=(x<<3)+(x<<1)+ch-'0'; 31 ch=getchar(); 32 } 33 return x*flag; 34 } 35 inline void add(int u,int v) 36 { 37 num++; 38 edge[num].next=head[u]; 39 head[u]=num; 40 edge[num].to=v; 41 } 42 void dfs1(int x,int pa) 43 { 44 size[x]=1; 45 dep[x]=dep[pa]+1; 46 for (int i=head[x];i;i=edge[i].next) 47 { 48 int v=edge[i].to; 49 if (v==pa) continue; 50 fa[v]=x; 51 dfs1(v,x); 52 size[x]+=size[v]; 53 if (size[son[x]]<size[v]) 54 son[x]=v; 55 } 56 } 57 void dfs2(int x,int tp) 58 { 59 top[x]=tp; 60 if (son[x]) 61 dfs2(son[x],tp); 62 for (int i=head[x];i;i=edge[i].next) 63 { 64 int v=edge[i].to; 65 if (v==fa[x]||v==son[x]) continue; 66 dfs2(v,v); 67 } 68 } 69 int lca(int x,int y) 70 { 71 while (top[x]!=top[y]) 72 { 73 if (dep[top[x]]<dep[top[y]]) swap(x,y); 74 x=fa[top[x]]; 75 } 76 if (dep[x]<dep[y]) return x; 77 return y; 78 } 79 int dis(int x,int y) 80 { 81 return dep[x]+dep[y]-(dep[lca(x,y)]<<1); 82 } 83 void get_root(int x,int pa) 84 { 85 size[x]=1; 86 int ret=0; 87 for (int i=head[x];i;i=edge[i].next) 88 { 89 int v=edge[i].to; 90 if (v==pa||vis[v]) continue; 91 get_root(v,x); 92 size[x]+=size[v]; 93 if (size[v]>ret) ret=size[v]; 94 } 95 if (Size-size[x]>ret) ret=Size-size[x]; 96 if (ret<minsize) minsize=ret,root=x; 97 } 98 void solve(int x,int pa) 99 { 100 vis[x]=1; 101 FA[x]=pa; 102 for (int i=head[x];i;i=edge[i].next) 103 { 104 int v=edge[i].to; 105 if (vis[v]) continue; 106 minsize=n;Size=size[v]; 107 get_root(v,x); 108 solve(root,x); 109 } 110 } 111 void update(int &rt,int l,int r,int x,int k) 112 { 113 if (!rt) rt=++pos; 114 sum[rt]+=k; 115 if (l==r) 116 return; 117 int mid=(l+r)>>1; 118 if (x<=mid) update(ch[rt][0],l,mid,x,k); 119 else update(ch[rt][1],mid+1,r,x,k); 120 } 121 int query(int rt,int l,int r,int L,int R) 122 { 123 if (!rt) return 0; 124 if (l>=L&&r<=R) 125 return sum[rt]; 126 int mid=(l+r)>>1; 127 int s=0; 128 if (L<=mid) s+=query(ch[rt][0],l,mid,L,R); 129 if (R>mid) s+=query(ch[rt][1],mid+1,r,L,R); 130 return s; 131 } 132 void change(int u,int w) 133 { 134 update(RT[u],0,n,0,w); 135 for (int i=u;FA[i];i=FA[i]) 136 { 137 int d=dis(u,FA[i]); 138 update(RT[FA[i]],0,n,d,w); 139 update(RT[i+n],0,n,d,w); 140 } 141 } 142 void ask(int u,int k) 143 { 144 ans+=query(RT[u],0,n,0,k); 145 for (int i=u;FA[i];i=FA[i]) 146 { 147 int d=dis(u,FA[i]); 148 if (d>k) continue; 149 ans+=query(RT[FA[i]],0,n,0,k-d); 150 ans-=query(RT[i+n],0,n,0,k-d); 151 } 152 } 153 int main() 154 {int u,v; 155 cin>>n>>m; 156 for (int i=1;i<=n;i++) 157 val[i]=gi(); 158 for (int i=1;i<=n-1;i++) 159 { 160 u=gi();v=gi(); 161 add(u,v);add(v,u); 162 } 163 dfs1(1,0); 164 dfs2(1,1); 165 minsize=Size=n; 166 get_root(1,0); 167 solve(root,0); 168 for (int i=1;i<=n;i++) 169 change(i,val[i]); 170 ans=0; 171 for (int i=1;i<=m;i++) 172 { 173 int opt=gi(); 174 int x=gi(),y=gi(); 175 if (opt==0) 176 { 177 x^=ans;y^=ans; 178 ans=0; 179 ask(x,y); 180 printf("%d\n",ans); 181 } 182 else 183 { 184 x^=ans;y^=ans; 185 change(x,y-val[x]); 186 val[x]=y; 187 } 188 } 189 return 0; 190 }