[HAOI2015] 树上操作

bzoj 4034 传送门

洛谷P3178 传送门

线段树+树链剖分裸题。

再次犯了把"=="打成了"="的智障错误。

还有忘记维护节点深度......

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\n",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 }
树上操作

猜你喜欢

转载自www.cnblogs.com/eternhope/p/9643156.html