洛谷P3384 【模板】树链剖分

题目描述

如题,已知一棵包含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%的数据: N10,M10

对于70%的数据: N10^3,M10^3

对于100%的数据: N10^5,M10^5

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

样例说明:

树的结构如下:

各个操作如下:

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

  1 #include<cmath>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #define maxn 100007
  7 using namespace std;
  8 long long read()
  9 {
 10     long long x=0,f=1;
 11     char ch=getchar();
 12     while(ch<'0'||ch>'9')
 13     {
 14         if(ch=='-')
 15             f=-1;
 16         ch=getchar();
 17     }
 18     while(ch>='0'&&ch<='9')
 19     {
 20         x=x*10+ch-'0';
 21         ch=getchar();
 22     }
 23     return x*f;
 24 }
 25 int n,m,num,root,p,opt,x,y,z,cnt;
 26 int head[maxn*2],a[maxn],son[maxn],fa[maxn],deep[maxn],size[maxn],top[maxn],pos[maxn],data[maxn],in[maxn],out[maxn];
 27 struct node
 28 {
 29     int v,nxt;
 30 } e[maxn];
 31 void add(int u,int v)
 32 {
 33     e[++num].v=v;
 34     e[num].nxt=head[u];
 35     head[u]=num;
 36     e[++num].v=u;
 37     e[num].nxt=head[v];
 38     head[v]=num;
 39 }
 40 struct NODE
 41 {
 42     int l,r,sum,flag;
 43 } tree[maxn*4];
 44 void dfs(int now)
 45 {
 46     size[now]=1;
 47     for(int i=head[now]; i; i=e[i].nxt)
 48         if(fa[now]!=e[i].v)
 49         {
 50             fa[e[i].v]=now;
 51             deep[e[i].v]=deep[now] + 1;
 52             dfs(e[i].v);
 53             size[now]+=size[e[i].v];
 54             if(size[son[now]]<size[e[i].v])
 55                 son[now]=e[i].v;
 56         }
 57 }
 58 void DFS(int now,int num)
 59 {
 60     top[now]=num;
 61     pos[now]=++cnt;
 62     in[now]=cnt;
 63     data[cnt]=a[now];
 64     if(son[now])
 65         DFS(son[now],num);
 66     for(int i=head[now]; i; i=e[i].nxt)
 67         if(fa[now]!=e[i].v&&e[i].v!=son[now])
 68             DFS(e[i].v,e[i].v);
 69     out[now]=cnt;
 70 }
 71 void build(int now,int l,int r)
 72 {
 73     tree[now].l=l;
 74     tree[now].r=r;
 75     tree[now].flag=0;
 76     if(l==r)
 77     {
 78         tree[now].sum=data[l];
 79         return ;
 80     }
 81     int mid=(l+r)>>1;
 82     build(now<<1,l,mid);
 83     build(now<<1|1,mid+1,r);
 84     tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum;
 85 }
 86 void down(int now)
 87 {
 88     if(tree[now].l==tree[now].r)
 89     {
 90         tree[now].flag=0;
 91         return ;
 92     }
 93     tree[now<<1].flag+=tree[now].flag;
 94     tree[now<<1|1].flag+=tree[now].flag;
 95     tree[now<<1].sum=(tree[now<<1].sum+tree[now].flag*(tree[now<<1].r-tree[now<<1].l+1))%p;
 96     tree[now<<1|1].sum=(tree[now<<1|1].sum+tree[now].flag*(tree[now<<1|1].r-tree[now<<1|1].l+1))%p;
 97     tree[now].flag=0;
 98 }
 99 void change(int now,int l,int r,int f)
100 {
101     while(tree[now].flag)
102         down(now);
103     if(tree[now].l>r||tree[now].r<l)
104         return ;
105     if(tree[now].l>=l&&tree[now].r<=r)
106     {
107         tree[now].flag=f;
108         (tree[now].sum+=f*(tree[now].r-tree[now].l+1))%=p;
109         return ;
110     }
111     change(now<<1,l,r,f);
112     change(now<<1|1,l,r,f);
113     tree[now].sum=(tree[now<<1].sum+tree[now<<1|1].sum)%p;
114 }
115 int query(int now,int l,int r)
116 {
117     while(tree[now].flag) down(now);
118     if(tree[now].l>r||tree[now].r<l)
119         return 0;
120     if(tree[now].l>=l&&tree[now].r<=r)
121         return tree[now].sum;
122     return (query(now<<1,l,r)+query(now<<1|1,l,r))%p;
123 }
124 void add1()
125 {
126     x=read(),y=read(),z=read(),z%=p;
127     while(top[x]!=top[y])
128     {
129         if(deep[top[x]]<deep[top[y]])
130             swap(x,y);
131         change(1,pos[top[x]],pos[x],z);
132         x=fa[top[x]];
133     }
134     if(deep[x]<deep[y])
135         swap(x,y);
136     change(1,pos[y],pos[x],z);
137 }
138 void add2()
139 {
140     x=read(),z=read(),z%=p;
141     change(1,in[x],out[x],z);
142 }
143 void query1()
144 {
145     x=read(),y=read();
146     int ans=0;
147     while(top[x]!=top[y])
148     {
149         if(deep[top[x]]<deep[top[y]])
150             swap(x,y);
151         ans=(ans+query(1,pos[top[x]],pos[x]))%p;
152         x=fa[top[x]];
153     }
154     if(deep[x]<deep[y])
155         swap(x,y);
156     (ans+=query(1,pos[y],pos[x]))%=p;
157     printf("%d\n",ans);
158 }
159 void query2()
160 {
161     x=read();
162     int ans=0;
163     (ans=query(1,in[x],out[x]))%=p;
164     printf("%d\n",ans);
165 }
166 int main()
167 {
168     n=read(),m=read(),root=read(),p=read();
169     for(int i=1; i<=n; ++i)
170         a[i]=read(),a[i]%=p;
171     for(int i=1,a,b; i<n; ++i)
172         a=read(),b=read(),add(a,b);
173     dfs(root);
174     DFS(root,root);
175     build(1,1,n);
176     while(m--)
177     {
178         opt=read();
179         if(opt==1)
180             add1();
181         else if(opt==3)
182             add2();
183         else if(opt==2)
184             query1();
185         else
186             query2();
187     }
188     return 0;
189 }
View Code

 

posted @ 2018-12-27 22:19  ~liweilin~  阅读(209)  评论(0编辑  收藏  举报