牧草种植
农民约翰有N个贫瘠的牧场(2 <= N <= 100,000),由N-1条双向道路连接,因此在任何两个牧场之间只有一条路径。贝西是一位喜欢吃草时间的奶牛,他经常抱怨牧场间道路上没有草。农夫约翰非常喜欢贝西,今天他终于在道路上种草了。他将使用由M个步骤组成的程序(1 <= M <= 100,000)。
在每一步都会发生以下两件事之一:
-
FJ会选择两个牧场,在两个牧场之间的每条道路上种上一块草地,或者,
-
贝西会询问某条路上有多少块草地,而农民约翰必须回答她的问题。
农夫约翰是一个非常贫穷的柜台 - 帮助他回答贝西的问题!
给出一棵Ñ个节点的树,有米个操作,操作为将一条路径上的边权加一或询问某条边的权值。
输入输出格式
输入格式:
*第1行:两个空格分隔的整数N和M.
*第2..N行:两个空格分隔的整数,用于描述道路的端点。
*第N + 1..N + M行:第i + 1行描述第i步。该行的第一个字符是P或Q,它描述了FJ是种草还是简单查询。其后是两个空格分隔的整数A_i和B_i(1 <= A_i,B_i <= N),它们描述了FJ的动作或查询。
输出格式:
*第1行.. ???:每行都有查询的答案,与查询出现在输入中的顺序相同。
输入输出样例
输入样例#1: 复制
4 6 1 4 2 4 3 4 P 2 3 P 1 3 Q 3 4 P 1 4 问2 4 Q 1 4
输出样例#1: 复制
2 1 2
题 解
首先不要在意翻译了。。。。
这是一个好题,关于树链剖分的边转点
我们要怎么实现边转点呢?
可以这么想,因为每两个点之间都只有一个边相连,我们可以考虑把值赋给深度深的,这样的询问的话,我们就只要在最后不计算lca的值就ok了
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const int N=500001; int head[N],fa[N],dep[N]; struct node{ int to,next; }e[N]; int ch[N],sum[N],a[N],l[N],top[N],lazy[N]; int size[N],son[N]; void build(int root,int l,int r) { int mid=l+r>>1; if(l==r) { sum[root]=a[l]; //cout<<a[l]<<' '<<l<<endl; return ; } build(root<<1,l,mid); build(root<<1|1,mid+1,r); sum[root]=sum[root<<1]+sum[root<<1|1]; return ; } void push(int root,int l,int r) { int mid=l+r>>1; lazy[root<<1]+=lazy[root]; lazy[root<<1|1]+=lazy[root]; sum[root<<1|1]+=lazy[root]*(r-mid); sum[root<<1]+=lazy[root]*(mid-l+1); lazy[root]=0; return ; } void update(int root,int left,int right,int l,int r,int k) { if(l<=left&&r>=right) { sum[root]+=k*(right-left+1); lazy[root]+=k; return ; } if(l>right||r<left)return ; int mid=left+right>>1; if(lazy[root])push(root,left,right); if(mid>=l) update(root<<1,left,mid,l,r,k); if(mid<r) update(root<<1|1,mid+1,right,l,r,k); sum[root]=sum[root<<1]+sum[root<<1|1]; return ; } int query(int root,int left,int right,int l,int r) { if(l<=left&&r>=right) { return sum[root]; } if(l>right||r<left)return 0; int mid=left+right>>1; if(lazy[root])push(root,left,right); int a=0,b=0; if(mid>=l) a=query(root<<1,left,mid,l,r); if(mid<r) b=query(root<<1|1,mid+1,right,l,r); return a+b; } void dfs1(int x) { size[x]=1; for(int i=head[x];i;i=e[i].next) { int v=e[i].to; if(!dep[v]) { dep[v]=dep[x]+1; fa[v]=x; dfs1(v); size[x]+=size[v]; if(size[v]>size[son[x]])son[x]=v; } } return; } int tot=0; void dfs2(int x,int t) { l[x]=++tot;a[tot]=ch[x];top[x]=t; if(son[x])dfs2(son[x],t); for(int i=head[x];i;i=e[i].next) { int v=e[i].to; if(v!=fa[x]&&v!=son[x]) dfs2(v,v); } return ; } int num=0; void add(int from,int to) { num++; e[num].to=to; e[num].next=head[from]; head[from]=num; } void cap1(int x,int y) { int fy=top[y],fx=top[x]; while(fy!=fx) { if(dep[fx]<dep[fy]) { swap(fx,fy);swap(x,y); } update(1,1,tot,l[fx],l[x],1); x=fa[fx]; fx=top[x]; } if(l[x]>l[y]) swap(x,y); update(1,1,tot,l[son[x]],l[y],1); return ; } int cap2(int x,int y) { int maxx=0; int fy=top[y],fx=top[x]; while(fy!=fx) { if(dep[fx]<dep[fy]) { swap(fx,fy);swap(x,y); } maxx+=query(1,1,tot,l[fx],l[x]); x=fa[fx]; fx=top[x]; } if(l[x]>l[y]) swap(x,y); maxx+=query(1,1,tot,l[son[x]],l[y]); return maxx; } int read() { int x=0,w=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*w; } int main() { int n,m; n=read();m=read(); for(int i=1;i<n;i++) { int x,y; x=read();y=read(); add(x,y);add(y,x); } fa[1]=1; dep[1]=1; dfs1(1); dfs2(1,1); build(1,1,n); for(int i=1;i<=m;i++) { char qwq; cin>>qwq; if(qwq=='P') { int x,y; x=read();y=read(); cap1(x,y); } else { int x,y; x=read();y=read(); printf("%d\n",cap2(x,y)); } } return 0; }