震波

震波

 

写完捉迷藏之后这道题就很显然了。对于每一个点x维护其子树中每一个点到x的距离,并以此为下标动态开点建立线段树,线段树维护区间和,同时再求出其子树中每一个点到fa[x]的距离,并以此动态开点建立线段树。

关于线段树的点数,我感觉是要开nlog^2的,然而开不下,所以尽量开吧。

貌似bzoj上卡常...反正我没有被卡。

  1 /**************************************************************
  2     Problem: 3730
  3     User: hyghb
  4     Language: C++
  5     Result: Accepted
  6     Time:13104 ms
  7     Memory:185712 kb
  8 ****************************************************************/
  9  
 10 #include<bits/stdc++.h>
 11 #define mid ((l+r)>>1)
 12 #define Rs t[o].ls
 13 #define Ls t[o].rs
 14 using namespace std;
 15 const int inf=1e5+10;
 16 int n,m,val[inf],last;
 17 int tot,fi[inf],nxt[inf<<1],to[inf<<1];
 18 void link(int x,int y){
 19     to[++tot]=y;nxt[tot]=fi[x];fi[x]=tot;
 20 }
 21 int top[inf],Fa[inf],dep[inf],siz[inf],son[inf];
 22 void dfs1(int x){
 23     siz[x]=1;
 24     for(int i=fi[x];i;i=nxt[i]){
 25         if(Fa[x]==to[i])continue;
 26         Fa[to[i]]=x;
 27         dep[to[i]]=dep[x]+1;
 28         dfs1(to[i]);
 29         siz[x]+=siz[to[i]];
 30         if(siz[to[i]]>siz[son[x]])son[x]=to[i];
 31     }
 32 }
 33 void dfs2(int x,int f){
 34     top[x]=f;
 35     if(son[x])dfs2(son[x],f);
 36     for(int i=fi[x];i;i=nxt[i]){
 37         if(top[to[i]])continue;
 38         dfs2(to[i],to[i]);
 39     }
 40 }
 41 int get_dis(int x,int y){
 42     int tmp=dep[x]+dep[y];
 43     while(top[x]!=top[y]){
 44         if(dep[top[x]]<dep[top[y]])swap(x,y);
 45         x=Fa[top[x]];
 46     }
 47     return tmp-min(dep[x],dep[y])*2+1;//防止0的情况
 48 }
 49 struct node{
 50     int ls,rs,val;
 51 }t[inf*150];//不能再大了啊...
 52 int segtree_size,maxr=100000,A[inf],B[inf];//A表示子树到当前点的的距离构成的线段树的根,B表示到当前点父亲距离构成线段树的根
 53 void add(int l,int r,int &o,int x,int y){
 54     if(!o)o=++segtree_size;
 55     t[o].val+=y;
 56     if(l==r)return ;
 57     if(x<=mid)add(l,mid,Ls,x,y);
 58     else add(mid+1,r,Rs,x,y);
 59 }
 60 int sum(int l,int r,int o,int L,int R){
 61     if(!o)return 0;
 62     if(l>=L&&r<=R)return t[o].val;
 63     int ans=0;
 64     if(mid>=L)ans+=sum(l,mid,Ls,L,R);
 65     if(mid<R)ans+=sum(mid+1,r,Rs,L,R);
 66     return ans;
 67 }
 68 int id,Min_size;
 69 int fa[inf];
 70 bool vis[inf];
 71 void getsize(int x,int f){
 72     siz[x]=1;
 73     for(int i=fi[x];i;i=nxt[i]){
 74         if(vis[to[i]] || to[i]==f)continue;
 75         getsize(to[i],x);
 76         siz[x]+=siz[to[i]];
 77     }
 78 }
 79 void getrt(int x,int f,int y){
 80     int tmp=-0x3fffffff;
 81     for(int i=fi[x];i;i=nxt[i]){
 82         if(vis[to[i]] || to[i]==f)continue;
 83         getrt(to[i],x,y);
 84         tmp=max(tmp,siz[to[i]]);
 85     }
 86     tmp=max(tmp,y-siz[x]);
 87     if(tmp<Min_size){
 88         Min_size=tmp;
 89         id=x;
 90     }
 91 }
 92 void dfs(int x,int f,int y){
 93     int dis1=get_dis(x,y),dis2=get_dis(x,fa[y]);
 94     add(1,maxr,A[y],dis1,val[x]);
 95     if(fa[y])add(1,maxr,B[y],dis2,val[x]);
 96     for(int i=fi[x];i;i=nxt[i]){
 97         if(vis[to[i]] || to[i]==f)continue;
 98         dfs(to[i],x,y);
 99     }
100 }
101 void Div(int x,int f){
102     getsize(x,0);
103     Min_size=0x3fffffff;
104     getrt(x,0,siz[x]);
105     int rt=id;
106     vis[rt]=1;
107     fa[rt]=f;
108     dfs(rt,0,rt);
109     for(int i=fi[rt];i;i=nxt[i]){
110         if(vis[to[i]])continue;
111         Div(to[i],rt);
112     }
113 }
114 int main()
115 {
116     scanf("%d%d",&n,&m);
117     for(int i=1;i<=n;i++)scanf("%d",&val[i]);
118     for(int i=1;i<n;i++){
119         int x,y;
120         scanf("%d%d",&x,&y);
121         link(x,y);link(y,x);
122     }
123     dfs1(1);
124     dfs2(1,1);
125     Div(1,0);
126     for(int i=1;i<=m;i++){
127         int opt,x,y;
128         scanf("%d",&opt);
129         scanf("%d%d",&x,&y);
130         x^=last;y^=last;
131         if(!opt){
132             y+=2;
133             last=0;
134             int now=x;
135             while(now){
136                 int dis=get_dis(now,x);
137                 last+=sum(1,maxr,A[now],1,y-dis);
138                 if(fa[now]){
139                     dis=get_dis(fa[now],x);
140                     last-=sum(1,maxr,B[now],1,y-dis);
141                 }
142                 now=fa[now];
143             }
144             printf("%d\n",last);
145         }
146         else {
147             int now=x;
148             while(now){
149                 add(1,maxr,A[now],get_dis(now,x),y-val[x]);
150                 if(fa[now])add(1,maxr,B[now],get_dis(fa[now],x),y-val[x]);
151                 now=fa[now];
152             }
153             val[x]=y;
154         }
155     }
156     return 0;
157 }
158 
View Code

 

转载于:https://www.cnblogs.com/hyghb/p/8478583.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值