码迷,mamicode.com
首页 > 其他好文 > 详细

树链剖分模板

时间:2017-06-12 14:58:24      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:log   add   upd   十分   sum   tps   nbsp   规模   str   

 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%的数据:N<=10,M<=10

对于70%的数据:N<=1000,M<=1000

对于100%的数据:N<=100000,M<=100000

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

样例说明:

树的结构如下:

技术分享

各个操作如下:

技术分享

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

 

 

半夜不适合敲代码,尤其这种结构体数组中多个定义的……

码程四十分钟,调程三小时……

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 int n,m,r,p,cnt,tot;
  7 int val[100010],head[100010];
  8 struct data{
  9     int next,to;
 10 }edge[200010];
 11 struct dt{
 12     int fa,son,size,deep,top,num,end;
 13     //son 重儿子 
 14     //size 子结点个数
 15     //top  当前结点所在链的顶结点 
 16 }tree[100010];
 17 struct tr{
 18     int sum,mark;
 19 }segtree[400010];
 20 void add_edge(int start,int ed){
 21     edge[++cnt].next=head[start];
 22     edge[cnt].to=ed;
 23     head[start]=cnt;
 24     return;
 25 }
 26 void dfs_weight(int u){
 27     tree[u].size=1;
 28     tree[u].son=0;
 29     for(int i=head[u];i;i=edge[i].next)
 30         if(edge[i].to!=tree[u].fa){
 31             tree[edge[i].to].fa=u;
 32             tree[edge[i].to].deep=tree[u].deep+1;
 33             dfs_weight(edge[i].to);
 34             tree[u].size+=tree[edge[i].to].size;
 35             if(tree[edge[i].to].size>tree[tree[u].son].size) tree[u].son=edge[i].to;
 36         }
 37     return;
 38 }
 39 void dfs_build(int u,int tp){
 40     tree[u].top=tp;
 41     tree[u].num=++tot;
 42     if(tree[u].son){
 43         dfs_build(tree[u].son,tp);
 44         for(int i=head[u];i;i=edge[i].next)
 45             if(edge[i].to!=tree[u].fa&&edge[i].to!=tree[u].son) dfs_build(edge[i].to,edge[i].to);
 46     }
 47     tree[u].end=tot;
 48     return;
 49 }
 50 void down(int pos,int ll,int mid,int rr){
 51     if(segtree[pos].mark){
 52         segtree[pos<<1].mark+=segtree[pos].mark;
 53         segtree[pos<<1|1].mark+=segtree[pos].mark;
 54         segtree[pos<<1].sum+=(mid-ll+1)*segtree[pos].mark;
 55         segtree[pos<<1].sum%=p;
 56         segtree[pos<<1|1].sum+=(rr-mid)*segtree[pos].mark;
 57         segtree[pos<<1|1].sum%=p;
 58         segtree[pos].mark=0;
 59         return;
 60     }
 61 }
 62 void update(int pl,int pr,int vl,int pos,int ll,int rr){
 63     if(pl<=ll&&pr>=rr){
 64         segtree[pos].mark+=vl;
 65         segtree[pos].sum+=(rr-ll+1)*vl;
 66         segtree[pos].sum%=p;
 67         return;
 68     }
 69     int mid=(ll+rr)>>1;
 70     down(pos,ll,mid,rr);
 71     if(pl<=mid) update(pl,pr,vl,pos<<1,ll,mid);
 72     if(pr>mid) update(pl,pr,vl,pos<<1|1,mid+1,rr);
 73     segtree[pos].sum=segtree[pos<<1].sum+segtree[pos<<1|1].sum;
 74     segtree[pos].sum%=p;
 75     return;
 76 }
 77 void add_val(int aa,int bb,int vl){
 78     int f1=tree[aa].top,f2=tree[bb].top;
 79     while(f1!=f2){
 80         if(tree[f1].deep<tree[f2].deep){
 81             update(tree[f2].num,tree[bb].num,vl,1,1,n);
 82             bb=tree[f2].fa;
 83             f2=tree[bb].top;
 84         }
 85         else{
 86             update(tree[f1].num,tree[aa].num,vl,1,1,n);
 87             aa=tree[f1].fa;
 88             f1=tree[aa].top;
 89         }
 90     }
 91     if(tree[aa].deep<tree[bb].deep) update(tree[aa].num,tree[bb].num,vl,1,1,n);
 92     else update(tree[bb].num,tree[aa].num,vl,1,1,n);
 93     return;
 94 }
 95 int ask(int pl,int pr,int pos,int ll,int rr){
 96     if(pl<=ll&&pr>=rr) return segtree[pos].sum;
 97     int mid=(ll+rr)>>1;
 98     down(pos,ll,mid,rr);
 99     int ans=0;
100     if(pl<=mid){
101         ans+=ask(pl,pr,pos<<1,ll,mid);
102         ans%=p; 
103     }
104     if(pr>mid){
105         ans+=ask(pl,pr,pos<<1|1,mid+1,rr);
106         ans%=p;
107     }
108     return ans;
109 }
110 int ask_some(int aa,int bb){
111     int f1=tree[aa].top,f2=tree[bb].top;
112     int ans=0;
113     while(f1!=f2){
114         if(tree[f1].deep<tree[f2].deep){
115             ans+=ask(tree[f2].num,tree[bb].num,1,1,n);
116             ans%=p;
117             bb=tree[f2].fa;
118             f2=tree[bb].top;
119         }
120         else{
121             ans+=ask(tree[f1].num,tree[aa].num,1,1,n);
122             ans%=p;
123             aa=tree[f1].fa;
124             f1=tree[aa].top;
125         }
126     }
127     if(tree[aa].deep<tree[bb].deep){
128         ans+=ask(tree[aa].num,tree[bb].num,1,1,n);
129         ans%=p;
130     }
131     else{
132         ans+=ask(tree[bb].num,tree[aa].num,1,1,n);
133         ans%=p;
134     }
135     return ans;
136 }
137 int main(){
138     scanf("%d%d%d%d",&n,&m,&r,&p);
139     for(int i=1;i<=n;i++) scanf("%d",&val[i]);
140     int x,y;
141     for(int i=1;i<n;i++){
142         scanf("%d%d",&x,&y);
143         add_edge(x,y);
144         add_edge(y,x);
145     }
146     tree[r].deep=0;
147     dfs_weight(r);
148     dfs_build(r,r);; 
149     for(int i=1;i<=n;i++) update(tree[i].num,tree[i].num,val[i],1,1,n);
150     int od,a,b,c;
151     for(int i=1;i<=m;i++){
152         scanf("%d",&od);
153         if(od==1){
154             scanf("%d%d%d",&a,&b,&c);
155             add_val(a,b,c);
156             continue;
157         }
158         if(od==2){
159             scanf("%d%d",&a,&b);
160             printf("%d\n",ask_some(a,b));
161             continue;
162         }
163         if(od==3){
164             scanf("%d%d",&a,&b);
165             update(tree[a].num,tree[a].end,b,1,1,n);
166             continue;
167         }
168         if(od==4){
169             scanf("%d",&a);
170             printf("%d\n",ask(tree[a].num,tree[a].end,1,1,n));
171             continue;
172         }
173     }
174     return 0;
175 }

 

树链剖分模板

标签:log   add   upd   十分   sum   tps   nbsp   规模   str   

原文地址:http://www.cnblogs.com/sdfzxh/p/6992527.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!