【USACO 2011 December Gold】Grass Planting种草 树链剖分

题目描述

  农夫约翰有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 
#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(rreturn 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(rreturn;
    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;iint 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]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<"\n";
        }else{
            int L=Getint(),r=Getint(),f1=top[L],f2=top[r];
            while(f1!=f2){
                if(dep[f1]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;
}

转载于:https://www.cnblogs.com/Cedric341561/p/6811012.html

你可能感兴趣的:(【USACO 2011 December Gold】Grass Planting种草 树链剖分)