线段树+树链剖分裸题。
再次犯了把"=="打成了"="的智障错误。
还有忘记维护节点深度......
pengzhou:啊,这是15年省选题,水吧?
我:嗯......
上代码吧。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define ll long long 5 using namespace std; 6 7 int n,m; 8 int hd[100005],to[200005],nx[200005],ec; 9 int in[100005],out[100005],pos[100005],cc; 10 int bv[100005]; 11 int sz[100005],d[100005],f[100005],son[100005],tp[100005]; 12 ll v[400005],lz[400005]; 13 int lb[400005],rb[400005]; 14 15 void edge(int af,int at) 16 { 17 to[++ec]=at; 18 nx[ec]=hd[af]; 19 hd[af]=ec; 20 } 21 22 void pre(int p,int fa) 23 { 24 f[p]=fa; 25 sz[p]=1; 26 d[p]=d[fa]+1; 27 for(int i=hd[p];i;i=nx[i]) 28 { 29 if(to[i]==fa)continue; 30 pre(to[i],p); 31 sz[p]+=sz[to[i]]; 32 if(sz[to[i]]>sz[son[p]])son[p]=to[i]; 33 } 34 } 35 36 void findtp(int p) 37 { 38 in[p]=++cc; 39 pos[cc]=p; 40 if(p==son[f[p]])tp[p]=tp[f[p]]; 41 else tp[p]=p; 42 if(son[p])findtp(son[p]); 43 for(int i=hd[p];i;i=nx[i]) 44 { 45 if(to[i]!=f[p]&&to[i]!=son[p])findtp(to[i]); 46 } 47 out[p]=cc; 48 } 49 50 void pushup(int p) 51 { 52 v[p]=v[p<<1]+v[p<<1|1]; 53 } 54 55 void pushdown(int p) 56 { 57 if(!lz[p])return; 58 v[p<<1]+=lz[p]*(ll)(rb[p<<1]-lb[p<<1]+1); 59 v[p<<1|1]+=lz[p]*(ll)(rb[p<<1|1]-lb[p<<1|1]+1); 60 lz[p<<1]+=lz[p]; 61 lz[p<<1|1]+=lz[p]; 62 lz[p]=0; 63 } 64 65 void build(int num,int l,int r) 66 { 67 lb[num]=l,rb[num]=r; 68 if(l==r) 69 { 70 v[num]=(ll)bv[pos[l]]; 71 return; 72 } 73 int mid=(l+r)>>1; 74 build(num<<1,l,mid); 75 build(num<<1|1,mid+1,r); 76 pushup(num); 77 } 78 79 void add(int num,int l,int r,ll val) 80 { 81 if(l<=lb[num]&&r>=rb[num]) 82 { 83 lz[num]+=val; 84 v[num]+=val*(ll)(rb[num]-lb[num]+1); 85 return; 86 } 87 pushdown(num); 88 int mid=(lb[num]+rb[num])>>1; 89 if(l<=mid)add(num<<1,l,r,val); 90 if(r>mid)add(num<<1|1,l,r,val); 91 pushup(num); 92 } 93 94 ll sum(int num,int l,int r) 95 { 96 if(l<=lb[num]&&r>=rb[num])return v[num]; 97 ll ret=0; 98 pushdown(num); 99 int mid=(lb[num]+rb[num])>>1; 100 if(l<=mid)ret+=sum(num<<1,l,r); 101 if(r>mid)ret+=sum(num<<1|1,l,r); 102 return ret; 103 } 104 105 void ask(int x) 106 { 107 int y=1; 108 ll ret=0; 109 while(tp[x]!=tp[y]) 110 { 111 if(d[tp[x]]<d[tp[y]])swap(x,y); 112 ret+=sum(1,in[tp[x]],in[x]); 113 x=f[tp[x]]; 114 } 115 if(d[x]>d[y])swap(x,y); 116 ret+=sum(1,in[x],in[y]); 117 printf("%lld ",ret); 118 } 119 120 int main() 121 { 122 scanf("%d%d",&n,&m); 123 for(int i=1;i<=n;i++)scanf("%d",&bv[i]); 124 for(int i=1;i<n;i++) 125 { 126 int ff,tt; 127 scanf("%d%d",&ff,&tt); 128 edge(ff,tt); 129 edge(tt,ff); 130 } 131 pre(1,1); 132 findtp(1); 133 build(1,1,n); 134 for(int i=1;i<=m;i++) 135 { 136 int op,p; 137 scanf("%d%d",&op,&p); 138 if(op==1) 139 { 140 int a; 141 scanf("%d",&a); 142 add(1,in[p],in[p],(ll)a); 143 } 144 if(op==2) 145 { 146 int a; 147 scanf("%d",&a); 148 add(1,in[p],out[p],(ll)a); 149 } 150 if(op==3)ask(p); 151 } 152 }