BZOJ 3730 震波

Posted Z-Y-Y-S

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

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 }

 

以上是关于BZOJ 3730 震波的主要内容,如果未能解决你的问题,请参考以下文章

Bzoj3730: 震波

BZOJ3730震波 动态树分治+线段树

bzoj 3730 震波 (动态点分治)

bzoj3730. 震波

[bzoj3730] 震波

BZOJ 3730 震波