「LuoguP3384」【模板】树链剖分

题目描述

如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

输入输出格式

输入格式:

第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。

接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)

接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:

操作1: 1 x y z

操作2: 2 x y

操作3: 3 x z

操作4: 4 x

输出格式:

输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模

输入输出样例

输入样例#1: 复制
5 5 2 24
7 3 7 8 0 
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3
输出样例#1: 复制
2
21

说明

时空限制:1s,128M

数据规模:

对于30%的数据: N≤10,M≤10

对于70%的数据: N≤10^3,M≤10^3

对于100%的数据: N≤10^5,M≤10^5

其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233

样例说明:

树的结构如下:

各个操作如下:

故输出应依次为2、21(重要的事情说三遍:记得取模)

题解

我也是会树剖的女人了!!!嗷嗷嗷嗷嗷嗷嗷嗷嗷嗷

模板题嘛QAQ,也没什么好讲的

剖了之后,对于操作1和2,在求lca的过程中做

对于操作3和4,直接在dfn[x]和dfn[x]+siz[x]-1上搞事就星了

其实操作1和2可以用树上前缀和水水水水水水(不对要随时询问好像布星QAQ)

  1 #include<cstdio>
  2 #include<iostream>
  3 using namespace std;
  4 const int MAXN=2e5+7;
  5 int val[MAXN];//点权
  6 //以下建原树
  7 struct emm{
  8     int e,f;
  9 }b[4*MAXN];
 10 int h[MAXN];
 11 int tot=0;
 12 void con(int x,int y)
 13 {
 14     b[++tot].f=h[x];
 15     h[x]=tot;
 16     b[tot].e=y;
 17     b[++tot].f=h[y];
 18     h[y]=tot;
 19     b[tot].e=x;
 20     return;
 21 }
 22 //第一遍dfs
 23 int d[MAXN],fa[MAXN],top[MAXN],z[MAXN],siz[MAXN];
 24 void dfs(int x)
 25 {
 26     siz[x]=1;
 27     top[x]=x;
 28     int mac=0,macc=-1;
 29     for(int i=h[x];i;i=b[i].f)
 30     if(!d[b[i].e])
 31     {
 32         d[b[i].e]=d[x]+1;
 33         fa[b[i].e]=x;
 34         dfs(b[i].e);
 35         siz[x]+=siz[b[i].e];
 36         if(macc<siz[b[i].e]){mac=b[i].e,macc=siz[b[i].e];}
 37     }
 38     z[x]=mac;
 39     top[mac]=x;
 40     return;
 41 }
 42 //第二遍dfs
 43 int q[MAXN],dfn[MAXN];
 44 void dfss(int x)
 45 {
 46     q[++tot]=x;
 47     dfn[x]=tot;
 48     if(z[x])dfss(z[x]);
 49     for(int i=h[x];i;i=b[i].f)
 50     if(fa[b[i].e]==x&&b[i].e!=z[x])
 51     dfss(b[i].e);
 52     return;
 53 }
 54 //找top
 55 int fitop(int x)
 56 {
 57     if(top[x]==x)return x;
 58     return top[x]=fitop(top[x]);
 59 }
 60 //建树完成
 61 int n,m,s;
 62 long long mod;
 63 //以下线段树
 64 struct ahh{
 65     int l,r;
 66     long long v,laz;
 67 }a[8*MAXN];
 68 void build(int i,int ll,int rr)
 69 {
 70     a[i].l=ll;
 71     a[i].r=rr;
 72     if(ll==rr){a[i].v=val[q[ll]];return;}
 73     int mid=(ll+rr)>>1;
 74     build((i<<1),ll,mid);
 75     build(((i<<1)|1),mid+1,rr);
 76     a[i].v=a[(i<<1)].v+a[((i<<1)|1)].v%mod;
 77     return;
 78 }
 79 void add(int i,int ll,int rr,int k)
 80 {
 81     if(a[i].l==ll&&a[i].r==rr)
 82     {a[i].laz+=k;return;}
 83     a[i].v=(long long)a[i].v+(rr-ll+1)*k%mod;
 84     int mid=(a[i].l+a[i].r)>>1;
 85     if(rr<=mid)add((i<<1),ll,rr,k);
 86     else if(mid+1<=ll)add(((i<<1)|1),ll,rr,k);
 87     else {add((i<<1),ll,mid,k);add(((i<<1)|1),mid+1,rr,k);}
 88     return;
 89 }
 90 void pushtag(int i)
 91 {
 92     if(!a[i].laz)return;
 93     a[i].v=(long long)a[i].v+a[i].laz*(a[i].r-a[i].l+1)%mod;
 94     if(a[i].l==a[i].r){a[i].laz=0;return;}
 95     a[(i<<1)].laz+=a[i].laz;
 96     a[((i<<1)|1)].laz+=a[i].laz;
 97     a[i].laz=0;
 98     return;
 99 }
100 unsigned long long ans;
101 void find(int i,int ll,int rr)
102 {
103     pushtag(i);
104     if(a[i].l==ll&&a[i].r==rr){ans=(ans+a[i].v)%mod;return;}
105     int mid=(a[i].l+a[i].r)>>1;
106     if(rr<=mid)find((i<<1),ll,rr);
107     else if(ll>=mid+1)find(((i<<1)|1),ll,rr);
108     else {find((i<<1),ll,mid);find(((i<<1)|1),mid+1,rr);}
109     return;
110 }
111 //
112 int main()
113 {
114     //freopen("a.in","r",stdin);
115     scanf("%d%d%d%lld",&n,&m,&s,&mod);
116     for(int i=1;i<=n;++i)
117     scanf("%d",&val[i]);
118     for(int i=1;i<n;++i)
119     {
120         int x,y;
121         scanf("%d%d",&x,&y);
122         con(x,y);
123     }
124     d[s]=1;
125     dfs(s);
126     tot=0;
127     dfss(s);
128     for(int i=1;i<=n;++i)
129     top[i]=fitop(i);
130     build(1,1,n);
131     //run
132     for(int c=1;c<=m;++c)
133     {
134         int opt;
135         scanf("%d",&opt);
136         if(opt==1)
137         {
138             int x,y,z;
139             scanf("%d%d%d",&x,&y,&z);
140             //lca
141             while(top[x]!=top[y])
142             {
143                 if(d[top[x]]>d[top[y]])
144                 {
145                     add(1,dfn[top[x]],dfn[x],z);
146                     x=fa[top[x]];
147                 }
148                 else
149                 {
150                     add(1,dfn[top[y]],dfn[y],z);
151                     y=fa[top[y]];
152                 }
153             }
154             if(d[x]>d[y])add(1,dfn[y],dfn[x],z);
155             else add(1,dfn[x],dfn[y],z);
156         }
157         else if(opt==2)
158         {
159             int x,y;
160             scanf("%d%d",&x,&y);
161             ans=0;
162             while(top[x]!=top[y])
163             {
164                 if(d[top[x]]>d[top[y]])
165                 {
166                     find(1,dfn[top[x]],dfn[x]);
167                     ans%=mod;
168                     x=fa[top[x]];
169                 }
170                 else
171                 {
172                     find(1,dfn[top[y]],dfn[y]);
173                     ans%=mod;
174                     y=fa[top[y]];
175                 }
176             }
177             if(d[x]>d[y])find(1,dfn[y],dfn[x]);
178             else find(1,dfn[x],dfn[y]);
179             printf("%lld
",ans%mod);
180         }
181         else if(opt==3)
182         {
183             int x,z;
184             scanf("%d%d",&x,&z);
185             add(1,dfn[x],dfn[x]+siz[x]-1,z);
186         }
187         else
188         {
189             int x;
190             scanf("%d",&x);
191             ans=0;
192             find(1,dfn[x],dfn[x]+siz[x]-1);
193             printf("%lld
",ans%mod);
194         }
195     }
196     return 0;
197 }
原文地址:https://www.cnblogs.com/qwerta/p/9629817.html