「HAOI2015」「LuoguP3178」树上操作(树链剖分

题目描述

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:

操作 1 :把某个节点 x 的点权增加 a 。

操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。

操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

输入输出格式

输入格式:

第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 行每行两个正整数 from, to , 表示该树中存在一条边 (from, to) 。再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

输出格式:

对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

输入输出样例

输入样例#1: 复制
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
输出样例#1: 复制
6
9
13

说明

对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不

会超过 10^6 。

题解

先剖一下。

操作1:在dfn[x]处+=a

操作2:从dfn[x]到dfn[x]+siz[x]-1上区间+a

操作3:往上跳的同时ans+=find(dfn[top[x]],dfn[x])

几乎是阉割版的树剖了。

  1 /*
  2     qwerta
  3     P3178 [HAOI2015]树上操作
  4     Accepted
  5     100
  6     代码 C++,2.93KB
  7     提交时间 2018-09-11 17:00:43
  8     耗时/内存
  9     993ms, 24476KB
 10 */
 11 #include<cstdio>
 12 #include<iostream>
 13 using namespace std;
 14 #define LL long long
 15 const LL MAXN=100000+7;
 16 LL val[MAXN];
 17 struct emm{
 18     LL e,f;
 19 }b[2*MAXN];
 20 LL h[MAXN];
 21 LL tot=0;
 22 void con(LL x,LL y)
 23 {
 24     b[++tot].f=h[x];
 25     h[x]=tot;
 26     b[tot].e=y;
 27     b[++tot].f=h[y];
 28     h[y]=tot;
 29     b[tot].e=x;
 30     return;
 31 }
 32 LL d[MAXN],siz[MAXN],z[MAXN],fa[MAXN],top[MAXN];
 33 void dfs(LL x)
 34 {
 35     siz[x]=1,top[x]=x;
 36     LL mac=0,macc=-1;
 37     for(LL i=h[x];i;i=b[i].f)
 38     if(!d[b[i].e])
 39     {
 40         d[b[i].e]=d[x]+1;
 41         fa[b[i].e]=x;
 42         dfs(b[i].e);
 43         siz[x]+=siz[b[i].e];
 44         if(macc<siz[b[i].e]){mac=b[i].e,macc=siz[b[i].e];}
 45     }
 46     z[x]=mac;
 47     top[mac]=x;
 48     return;
 49 }
 50 LL q[MAXN],dfn[MAXN];
 51 void dfss(LL x)
 52 {
 53     q[++tot]=x;
 54     dfn[x]=tot;
 55     if(z[x])dfss(z[x]);
 56     for(LL i=h[x];i;i=b[i].f)
 57     if(fa[b[i].e]==x&&b[i].e!=z[x])
 58     dfss(b[i].e);
 59     return;
 60 }
 61 LL fitop(LL x)
 62 {
 63     if(top[x]==x)return x;
 64     return top[x]=fitop(top[x]);
 65 }
 66 struct ahh{
 67     LL l,r,mid;
 68     long long v,laz;
 69 }a[8*MAXN];
 70 #define lz (i<<1)
 71 #define rz ((i<<1)|1)
 72 #define amid a[i].mid
 73 void build(LL i,LL ll,LL rr)
 74 {
 75     a[i].l=ll;
 76     a[i].r=rr;
 77     if(ll==rr){a[i].v=val[q[ll]];return;}
 78     amid=(ll+rr)>>1;
 79     build(lz,ll,amid);
 80     build(rz,amid+1,rr);
 81     a[i].v=a[lz].v+a[rz].v;
 82     return;
 83 }
 84 void add(LL i,LL ll,LL rr,LL k)
 85 {
 86     if(a[i].l==ll&&a[i].r==rr){a[i].laz+=k;return;}
 87     a[i].v+=(rr-ll+1)*k;
 88     if(rr<=amid)add(lz,ll,rr,k);
 89     else if(amid+1<=ll)add(rz,ll,rr,k);
 90     else {add(lz,ll,amid,k);add(rz,amid+1,rr,k);}
 91     return;
 92 }
 93 long long ans=0;
 94 void pushtag(LL i)
 95 {
 96     if(!a[i].laz)return;
 97     a[i].v+=(a[i].r-a[i].l+1)*a[i].laz;
 98     if(a[i].l==a[i].r){a[i].laz=0;return;}
 99     a[lz].laz+=a[i].laz;
100     a[rz].laz+=a[i].laz;
101     a[i].laz=0;
102     return;
103 }
104 void find(LL i,LL ll,LL rr)
105 {
106     pushtag(i);
107     if(a[i].l==ll&&a[i].r==rr){ans+=a[i].v;return;}
108     if(rr<=amid)find(lz,ll,rr);
109     else if(amid+1<=ll)find(rz,ll,rr);
110     else {find(lz,ll,amid);find(rz,amid+1,rr);}
111     return;
112 }
113 LL s;
114 int main()
115 {
116     //freopen("a.in","r",stdin);
117     LL n,m;
118     scanf("%lld%lld",&n,&m);
119     for(LL i=1;i<=n;++i)
120     scanf("%lld",&val[i]);
121     for(LL i=1;i<n;++i)
122     {
123         LL u,v;
124         scanf("%lld%lld",&u,&v);
125         con(u,v);
126     }
127     s=1;
128     d[s]=1;
129     dfs(s);
130     tot=0;
131     dfss(s);
132     for(LL i=1;i<=n;++i)
133     top[i]=fitop(i);
134     build(1,1,n);
135     for(LL i=1;i<=m;++i)
136     {
137         LL opt;
138         scanf("%lld",&opt);
139         if(opt==1)
140         {
141             LL x,v;
142             scanf("%lld%lld",&x,&v);
143             add(1,dfn[x],dfn[x],v);
144         }
145         else if(opt==2)
146         {
147             LL x,v;
148             scanf("%lld%lld",&x,&v);
149             add(1,dfn[x],dfn[x]+siz[x]-1,v);
150         }
151         else
152         {
153             LL x;
154             scanf("%lld",&x);
155             ans=0;
156             while(x)
157             {
158                 find(1,dfn[top[x]],dfn[x]);
159                 x=fa[top[x]];
160             }
161             printf("%lld
",ans);
162         }
163     }
164     return 0;
165 }
原文地址:https://www.cnblogs.com/qwerta/p/9629928.html