4633 [Mz]树链剖分练习
时间限制: 1 s 空间限制: 64000 KB 题目等级 : 大师 Master
题目描述 Description
给定一棵结点数为n的树,初始点权均为0,有依次q个操作,每次操作有三个参数a,b,c,当a=1时,表示给b号结点到c号结点路径上的所有点(包括b,c,下同)权值都增加1,当a=2时,表示询问b号结点到c号结点路径上的所有点权值之和。
输入描述 Input Description
第一行,一个正整数n。
接下来n-1行,每行一对正整数x,y,表示x号结点和y号结点之间有一条边。
第n+1行,一个正整数q。
最后q行,每行一组正整数a,b,c,表示操作的三个参数。b和c可能相等。
保证数据都是合法的。
输出描述 Output Description
若干行,每行一个非负整数表示答案。
样例输入 Sample Input
5
1 2
2 3
1 4
2 5
5
1 4 5
2 1 5
1 1 3
2 5 3
2 4 3
样例输出 Sample Output
3
4
6
数据范围及提示 Data Size & Hint
共有10个测试点,对于第i个测试点,当1<=i<=4时,n=q=10^i,当5<=i<=10时,n=q=10000*i。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define maxn 10000*10 6 struct Edge{ int to,next,value; }e[maxn*2+10]; 7 struct Node{ int l,r,sum,lazy; }tre[maxn*5]; 8 int dep[maxn],pos[maxn],size[maxn],son[maxn],fa[maxn]; 9 int top[maxn],head[maxn],tot=0,n,visx; 10 void Add_Edge(int u,int v){ 11 e[++tot].to=v;e[tot].next=head[u]; 12 head[u]=tot; 13 } 14 void DFS_First(int now,int pre,int deepth){ 15 fa[now]=pre;size[now]=1;dep[now]=deepth; 16 for(int i=head[now];i;i=e[i].next){ 17 int v=e[i].to; 18 if(v!=pre&&!dep[v]){ 19 DFS_First(v,now,deepth+1); 20 size[now]+=size[v]; 21 if(!son[now]||size[son[now]]<size[v]) 22 son[now]=v; 23 } 24 } 25 } 26 void DFS_Second(int now,int Top){ 27 pos[now]=++visx;top[now]=Top; 28 if(son[now])DFS_Second(son[now],Top); 29 for(int i=head[now];i;i=e[i].next){ 30 int v=e[i].to; 31 if(v!=son[now]&&v!=fa[now])DFS_Second(v,v); 32 } 33 } 34 void Build(int now,int l,int r){ 35 tre[now].l=l;tre[now].r=r; 36 if(l==r)return; 37 int mid=(l+r)>>1; 38 Build(now<<1,l,mid);Build(now<<1|1,mid+1,r); 39 } 40 void down(int now){ 41 int k=tre[now].lazy; 42 tre[now<<1].lazy+=k;tre[now<<1|1].lazy+=k; 43 tre[now].lazy=0; 44 tre[now<<1].sum+=k*(tre[now<<1].r-tre[now<<1].l+1); 45 tre[now<<1|1].sum+=k*(tre[now<<1|1].r-tre[now<<1|1].l+1); 46 } 47 int query(int now,int l,int r){ 48 if(l<=tre[now].l&&tre[now].r<=r)return tre[now].sum; 49 if(tre[now].lazy)down(now); 50 int ans=0,mid=(tre[now].l+tre[now].r)>>1; 51 if(mid>=l)ans+=query(now<<1,l,r); 52 if(mid<r)ans+=query(now<<1|1,l,r); 53 tre[now].sum=tre[now<<1].sum+tre[now<<1|1].sum; 54 return ans; 55 } 56 int QuerySum(int u,int v){ 57 int ans=0; 58 while(top[u]!=top[v]){ 59 if(dep[top[u]] < dep[top[v]])swap(u,v); 60 ans+=query(1,pos[top[u]],pos[u]); 61 u=fa[top[u]]; 62 } 63 if(dep[u]>dep[v])swap(u,v); 64 ans+=query(1,pos[u],pos[v]); 65 return ans; 66 } 67 void UpDate(int now,int l,int r){ 68 if(l<=tre[now].l&&tre[now].r<=r){ 69 tre[now].lazy++; 70 tre[now].sum+=tre[now].r-tre[now].l+1; 71 return ; 72 } 73 if(tre[now].lazy)down(now); 74 int mid=(tre[now].l+tre[now].r)/2; 75 if(mid>=l)UpDate(now<<1,l,r); 76 if(mid<r)UpDate(now<<1|1,l,r); 77 tre[now].sum=tre[now<<1].sum+tre[now<<1|1].sum; 78 return ; 79 } 80 void Change(int u,int v){ 81 while(top[u]!=top[v]){ 82 if(dep[top[u]]<dep[top[v]])swap(u,v); 83 UpDate(1,pos[top[u]],pos[u]); 84 u=fa[top[u]]; 85 } 86 if(dep[u]>dep[v])swap(u,v); 87 UpDate(1,pos[u],pos[v]); 88 } 89 int main(){ 90 scanf("%d",&n); 91 int q,x,y,z; 92 for(int i=1,u,v;i<n;i++){ 93 scanf("%d%d",&u,&v); 94 Add_Edge(u,v);Add_Edge(v,u); 95 } 96 DFS_First(1,0,0); 97 DFS_Second(1,1); 98 Build(1,1,n); 99 100 scanf("%d",&q); 101 while(q--){ 102 scanf("%d%d%d",&x,&y,&z); 103 if(x==1)Change(y,z); 104 else printf("%d ",QuerySum(y,z)); 105 } 106 return 0; 107 }