震波

在一片土地上有 $N$ 个城市,通过 $N-1$ 条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为 $1$,其中第 $i$ 个城市的价值为 $value[i]$。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理 $M$ 次操作:
- $0~x~k$ 表示发生了一次地震,震中城市为 $x$ ,影响范围为 $k$ ,所有与 $x$ 距离不超过 $k$ 的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
- $1~x~y$ 表示第$x$个城市的价值变成了 $y$ 。
为了体现程序的在线性,操作中的 $x$ 、$y$ 、$k$ 都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为 $0$ 。
 
 
 
 
Solution
考虑建出点分树,每一个点开一棵以长度为下标的线段树。
查询时可以一步步往上跳。假设他到父亲的权值为t,每此查询与x距离为k k+t ...的点。
可是这样会算重。
那么可以在每个点再开一棵线段树,下标为点到他点分树上父亲的权值。
每次减去第二棵线段树中k+t的值。也就是自己与父亲相同的贡献
卡常毒题
orz邵神树状数组常树优秀
 
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<cmath>
  7 #define maxn 200006
  8 using namespace std;
  9 int n,m,head[maxn],a[maxn],val[maxn],siz,tot,deep[maxn];
 10 int f[maxn],vis[maxn],par[maxn],sz[maxn],rt;
 11 int cnt,root[maxn],st[maxn][20],sc,dfn[maxn],l2[maxn];
 12 struct node{
 13     int v,nex;
 14 }e[maxn];
 15 struct no{
 16     int ls,rs,v;
 17 }tr[maxn*140];
 18 inline void lca(int k,int fa){
 19     st[dfn[k]=++sc][0]=deep[k]=deep[fa]+1;
 20     for(int i=head[k];i;i=e[i].nex)if(e[i].v!=fa)lca(e[i].v,k),st[++sc][0]=deep[k];
 21 }
 22 inline void add(int &k,int l,int r,int pl,int v){
 23     if(!k)k=++cnt;
 24     if(l==r){tr[k].v+=v;return;}
 25     int mid=l+r>>1;
 26     if(pl<=mid)add(tr[k].ls,l,mid,pl,v);
 27     else add(tr[k].rs,mid+1,r,pl,v);
 28     tr[k].v=tr[tr[k].ls].v+tr[tr[k].rs].v;
 29 }
 30 inline int ask(int k,int l,int r,int pl){
 31     if(!k||pl<0)return 0;
 32     if(l==r)return tr[k].v;
 33     int mid=l+r>>1;
 34     if(pl<=mid)return ask(tr[k].ls,l,mid,pl);
 35     else return tr[tr[k].ls].v+ask(tr[k].rs,mid+1,r,pl);
 36     
 37 }
 38 inline int dis(int x,int y){
 39     if(dfn[y]<dfn[x])swap(x,y);
 40     int i=l2[dfn[y]-dfn[x]+1];
 41     int dl=min(st[dfn[x]][i],st[dfn[y]-(1<<i)+1][i]);
 42     return deep[x]+deep[y]-(dl<<1);
 43 }
 44 inline void dfs(int o,int la,int k,int fa){
 45     add(root[o],0,n,dis(o,k),val[k]);
 46     if(la)add(root[o+n],0,n,dis(k,la),val[k]);
 47     sz[k]=1;
 48     for(int i=head[k];i;i=e[i].nex){
 49         if(e[i].v==fa||vis[e[i].v])continue;
 50         dfs(o,la,e[i].v,k);
 51         sz[k]+=sz[e[i].v];
 52     }
 53 }
 54 inline void findr(int k,int fa){
 55     sz[k]=1;f[k]=0;
 56     for(int i=head[k];i;i=e[i].nex){
 57         if(e[i].v==fa||vis[e[i].v])continue;
 58         findr(e[i].v,k);
 59         sz[k]+=sz[e[i].v];
 60         f[k]=max(f[k],sz[e[i].v]);
 61     }
 62     f[k]=max(f[k],siz-sz[k]);
 63     if(f[k]<f[rt])rt=k;
 64 }
 65 inline void work(int k,int la){
 66     vis[k]=1;
 67     dfs(k,la,k,0);
 68     for(int i=head[k];i;i=e[i].nex){
 69         if(!vis[e[i].v]){
 70             siz=sz[e[i].v];rt=0;findr(e[i].v,k);
 71             par[rt]=k;
 72             work(rt,k);
 73         }
 74     }
 75 }
 76 inline int R(){
 77     int v=0;char ch;
 78     while(!isdigit(ch=getchar()));v=ch-48;
 79     while(isdigit(ch=getchar()))v=(v<<1)+(v<<3)+ch-48;
 80     return v;
 81 }
 82 int main()
 83 {
 84     n=R();m=R();
 85     for(int i=1;i<=n;i++)val[i]=R();
 86     for(int i=1,t1,t2;i<n;i++){
 87         t1=R();t2=R();
 88         e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
 89         e[++tot].v=t1;e[tot].nex=head[t2];head[t2]=tot;
 90     }
 91     lca(1,0);
 92     for(int i=2;i<=sc;i++)l2[i]=l2[i/2]+1;
 93     for(int j=1;j<=l2[sc];j++)
 94         for(int i=1;i+(1<<j)<=sc+1;i++)st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
 95     rt=0;f[0]=1e9;siz=n;findr(1,0);
 96     work(rt,0);
 97     int ans=0;
 98     for(int i=1,op,y,x,k;i<=m;i++){
 99         op=R();
100         if(op==0){
101             x=R();k=R();
102             x^=ans,k^=ans;
103             ans=0;int fi=x;
104             for(int d=0;x;){
105                 ans+=ask(root[x],0,n,k-d);d=dis(par[x],fi);
106                 if(par[x])ans-=ask(root[n+x],0,n,k-d);
107                 x=par[x];
108             }
109             printf("%d\n",ans);
110         }
111         if(op==1){
112             x=R();y=R();
113             x^=ans;y^=ans;
114             int fi=x;
115             for(int d=0;x;){
116                 add(root[x],0,n,d,y-val[fi]);d=dis(fi,par[x]);
117                 if(par[x])add(root[n+x],0,n,d,y-val[fi]);
118                 x=par[x];
119             }
120             val[fi]=y;
121         }
122     }
123     return 0;
124 }
View Code

 

 

posted @ 2019-04-05 08:23  liankewei123456  阅读(297)  评论(0编辑  收藏  举报