题目描述
农夫约翰有N块贫瘠的牧场(2 <= N <= 100,000),有N-1条双向道路将这N个牧场连接了起来,每两个牧场间都有且仅有一条路径可相互到达。著名奶牛贝西经常抱怨:为什么连接牧场的道路上没有草可吃呢?
约翰非常喜欢贝西,今天约翰终于决定要在道路上种草了。约翰的种草工作被分成了M(1 <= M <=100,000)步操作。
在每一步中,下列两个事件中的一个会发生:
1.约翰会选择两个牧场,沿着两个牧场间的路径,在路径上的每一条道路上都种植1株牧草;
2.贝西会向约翰提问:在一条指定的道路上,种植了多少株牧草;
请帮助约翰回答贝西的问题。
题目大意
实现两个操作:从u-v的路径边权+1,询问从u-v的路径边权。
数据范围
(1 <= M <=100,000)
(2 <= N <= 100,000)
样例输入
4 6
1 4
2 4
3 4
P 2 3
P 1 3
Q 3 4
P 1 4
Q 2 4
Q 1 4
样例输出
2
1
2
解题思路
树链剖分模板题
代码
#include <bits/stdc++.h>
#define Maxn 100005
using namespace std;
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
inline char Getch(){char ch=getchar();while(ch!='P'&&ch!='Q')ch=getchar();return ch;}
struct NODE{int to,next;}e[Maxn*2];
struct node{int L,r,Sum,Add;}Tree[Maxn*4];
int n,q,cnt=0,dep[Maxn],size[Maxn],son[Maxn],mark[Maxn],fa[Maxn],top[Maxn],h[Maxn];
void AddEdge(int x,int y){e[++cnt]=(NODE){y,h[x]};h[x]=cnt;}
void dfs1(int x,int L,int d){
int Max=0;
dep[x]=d;
size[x]=1;
son[x]=0;
for(int p=h[x];p;p=e[p].next){
int y=e[p].to;
if(y==L)continue;
dfs1(y,x,d+1);
fa[y]=x;
size[x]+=size[y];
if(size[y]>Max){
Max=size[y];
son[x]=y;
}
}
}
void dfs2(int x,int L){
top[x]=L;
mark[x]=++cnt;
if(son[x])dfs2(son[x],L);
for(int p=h[x];p;p=e[p].next)
if(e[p].to!=fa[x]&&e[p].to!=son[x])
dfs2(e[p].to,e[p].to);
}
void PushDown(int v){
Tree[2*v].Add+=Tree[v].Add;
Tree[2*v+1].Add+=Tree[v].Add;
Tree[2*v].Sum+=Tree[v].Add*(Tree[2*v].r-Tree[2*v].L+1);
Tree[2*v+1].Sum+=Tree[v].Add*(Tree[2*v+1].r-Tree[2*v+1].L+1);
Tree[v].Add=0;
}
void PushUp(int v){
Tree[v].Sum=Tree[2*v].Sum+Tree[2*v+1].Sum;
}
void Build(int v,int L,int r){
Tree[v]=(node){L,r,0,0};
if(L==r)return;
Build(2*v,L,(L+r)/2);
Build(2*v+1,(L+r)/2+1,r);
}
long long Ask(int v,int L,int r){
if(r<Tree[v].L||Tree[v].r<L)return 0;
if(L<=Tree[v].L&&Tree[v].r<=r)return Tree[v].Sum;
PushDown(v);
return Ask(2*v,L,r)+Ask(2*v+1,L,r);
}
void Modify(int v,int L,int r){
if(r<Tree[v].L||Tree[v].r<L)return;
if(L<=Tree[v].L&&Tree[v].r<=r){
Tree[v].Sum+=(Tree[v].r-Tree[v].L+1);
Tree[v].Add++;
return;
}
PushDown(v);
Modify(2*v,L,r);
Modify(2*v+1,L,r);
PushUp(v);
}
int main(){
n=Getint();q=Getint();
for(int i=1;i<n;i++){
int x=Getint(),y=Getint();
AddEdge(x,y);
AddEdge(y,x);
}
cnt=0;
dfs1(1,0,1);
dfs2(1,1);
Build(1,1,cnt);
while(q--){
char ch=Getch();
if(ch=='Q'){
int L=Getint(),r=Getint(),f1=top[L],f2=top[r];
int Ans=0;
while(f1!=f2){
if(dep[f1]<dep[f2])swap(f1,f2),swap(L,r);
Ans+=Ask(1,mark[f1],mark[L]);
L=fa[f1];
f1=top[L];
}
if(L!=r){
if(dep[L]>dep[r])swap(L,r);
Ans+=Ask(1,mark[son[L]],mark[r]);
}
cout<<Ans<<"\n";
}else{
int L=Getint(),r=Getint(),f1=top[L],f2=top[r];
while(f1!=f2){
if(dep[f1]<dep[f2])swap(f1,f2),swap(L,r);
Modify(1,mark[f1],mark[L]);
L=fa[f1];
f1=top[L];
}
if(L!=r){
if(dep[L]>dep[r])swap(L,r);
Modify(1,mark[son[L]],mark[r]);
}
}
}
return 0;
}