suoi22 WRX知识树(dfs序)

把一条路径拆成到根的四个链(两端点、lca和fa[lca]),然后给dfs序中链的端点做单点修改、区间查询它的子树和再加上它原来的权值就可以了

  1 #include<bits/stdc++.h>
  2 #define pa pair<int,int>
  3 #define lowb(x) ((x)&(-(x)))
  4 #define REP(i,n0,n) for(i=n0;i<=n;i++)
  5 #define PER(i,n0,n) for(i=n;i>=n0;i--)
  6 #define MAX(a,b) ((a>b)?a:b)
  7 #define MIN(a,b) ((a<b)?a:b)
  8 #define CLR(a,x) memset(a,x,sizeof(a))
  9 #define rei register int
 10 using namespace std;
 11 typedef long long ll;
 12 const int maxn=1e6+10;
 13 
 14 inline ll rd(){
 15     ll x=0;char c=getchar();int neg=1;
 16     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
 17     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
 18     return x*neg;
 19 }
 20 
 21 int N,M;
 22 int eg[maxn*2][2],egh[maxn],ect;
 23 int v[maxn],fa[maxn],bfa[maxn];
 24 int lq[maxn*2][2],lqh[maxn],lca[maxn][2];
 25 int dfn[maxn][2],tot;
 26 int stk[maxn][2],sh;
 27 ll tr[maxn];
 28 int que[maxn];
 29 bool vis[maxn];
 30 
 31 inline void adeg(int a,int b){
 32     eg[++ect][0]=b;eg[ect][1]=egh[a];egh[a]=ect;
 33 }
 34 
 35 int getf(int x){return x==bfa[x]?x:bfa[x]=getf(bfa[x]);}
 36 
 37 inline void add(int x,ll y){
 38     for(;x>0&&x<=N;x+=lowb(x)) tr[x]+=y;
 39 }
 40 inline ll query(int x){
 41     ll re=0;for(;x>0;x-=lowb(x)) re+=tr[x];return re;
 42 }
 43 
 44 void dfs(){
 45     stk[sh=1][0]=1;stk[1][1]=egh[1];
 46     dfn[1][0]=tot=1;
 47     while(sh){
 48         int x=stk[sh][0],i=stk[sh][1],b=eg[i][0];
 49         vis[x]=1;
 50         if(!i){
 51             for(int j=lqh[x];j;j=lq[j][1]){
 52                 int c=lq[j][0];
 53                 if(vis[c]) lca[j>>1][0]=getf(c);
 54             }
 55             bfa[getf(x)]=fa[x];
 56             dfn[x][1]=tot;
 57             sh--;continue;
 58         }
 59         stk[sh][1]=eg[i][1];
 60         if(!vis[b]){
 61             fa[b]=x;stk[++sh][0]=b,stk[sh][1]=egh[b];
 62             dfn[b][0]=++tot;
 63         }
 64         
 65     }
 66 }
 67 
 68 int main(){
 69     //freopen(".in","r",stdin);
 70     rei i;
 71     N=rd(),M=rd();
 72     for(i=1;i<=N;i++) v[i]=rd();
 73     for(i=1;i<N;i++){
 74         int a=rd(),b=rd();
 75         adeg(a,b);adeg(b,a);
 76     }for(i=1;i<=N;i++) bfa[i]=i;
 77     for(i=1;i<=M;i++){
 78         int a=rd(),b=rd();
 79         if(!a){
 80             que[i]=b;
 81         }else{
 82             int c=rd(),d=rd();
 83             lca[i][1]=d;
 84             lq[i<<1][0]=b;lq[i<<1][1]=lqh[c];lqh[c]=i<<1;
 85             lq[i<<1|1][0]=c;lq[i<<1|1][1]=lqh[b];lqh[b]=i<<1|1;
 86         }
 87     }
 88     dfs();
 89     for(i=1;i<=M;i++){
 90         if(lca[i][0]){
 91             // printf("!%d %d %d\n",lca[i][0],lq[i<<1][0],lq[i<<1|1][0]);
 92             add(dfn[lca[i][0]][0],-lca[i][1]);
 93             if(fa[lca[i][0]]) add(dfn[fa[lca[i][0]]][0],-lca[i][1]);
 94             add(dfn[lq[i<<1][0]][0],lca[i][1]);
 95             add(dfn[lq[i<<1|1][0]][0],lca[i][1]);
 96             // cout<<"mmm"<<endl;
 97         }else{
 98             printf("%lld\n",v[que[i]]+query(dfn[que[i]][1])-query(dfn[que[i]][0]-1));
 99         }
100         
101     }
102     return 0;
103 }

 

转载于:https://www.cnblogs.com/Ressed/p/9735525.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值