[USACO11DEC]牧草种植Grass Planting(树链剖分)

题目

传送门

题解

这道题就是把树链剖分中的点标记改成了边的标记,然后我就不会做了;
我么发现,每一个点对应着多个孩子,但是只有一个父亲,于是我们就可以把某个点到父亲的点的边的权值转移到这个点上;
如何防止把最近公共祖先也标记上,这就是树链剖分的一点小变形,找完连头之后左端点+1;
还是对算法理解的不够深刻。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define lson (rt<<1)
#define rson (rt<<1|1)
const int maxn=1e6;
const int inf=1e9;
int read(){
    char ch=getchar(); int now=0,f=1;
    while (ch<'0'||ch>'9') {
   
   if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0'&&ch<='9'){now=(now<<1)+(now<<3)+ch-'0'; ch=getchar();}
    return now*f;}

int n,m,fa[maxn],son[maxn],deep[maxn],dfn[maxn],idfn[maxn],top[maxn],tot[maxn];
struct Edge{
    int next,to;
}edge[maxn<<1];
int num_edge=-1,head[maxn];

void add_edge(int from,int to)
{
    edge[++num_edge].next=head[from];
    edge[num_edge].to=to;
    head[from]=num_edge;
}

void dfs1(int x,int father,int depth)
{
    fa[x]=father;
    deep[x]=depth;
    tot[x]=1;
    int maxnow=-1;
    for (int i=head[x]; i!=-1; i=edge[i].next)
    {
        int to=edge[i].to;
        if (to!=father)
        {
            dfs1(to,x,depth+1);
            tot[x]+=tot[to];
            if (tot[to]>maxnow)
            {
                maxnow=tot[to];
                son[x]=to;
            }
        }
    }
}

int cnt=0;
void dfs2(int x,int tp)
{
    dfn[x]=++cnt;
    idfn[cnt]=x;
    top[x]=tp;
    if (!son[x]) return;
    dfs2(son[x],tp);
    for (int i=head[x]; i!=-1; i=edge[i].next)
    {
        int to=edge[i].to;
        if (to!=fa[x] && to!=son[x])
            dfs2(to,to);
    }
}

//Seg_Tree
int sum[maxn<<1|1],add[maxn<<1|1];
void pushup(int rt) {sum[rt]=sum[lson]+sum[rson];}
void pushdown(int rt,int ln,int rn)
{
    if (add[rt])
    {
        add[lson]+=add[rt];
        add[rson]+=add[rt];
        sum[lson]+=ln*add[rt];
        sum[rson]+=rn*add[rt];
        add[rt]=0;
    }
}

void change(int L,int R,int C,int l,int r,int rt)
{
    if (L<=l && r<=R) 
    {
        add[rt]+=C; sum[rt]+=C*(r-l+1);
        return;
    }
    int mid=(l+r)>>1;
    pushdown(rt,mid-l+1,r-mid);
    if (L<=mid) change(L,R,C,l,mid,lson);
    if (R>mid) change(L,R,C,mid+1,r,rson);
    pushup(rt);
}

int ques(int L,int R,int l,int r,int rt)
{
    if (L<=l && r<=R) return sum[rt];
    int mid=(l+r)>>1; int ans=0; 
    pushdown(rt,mid-l+1,r-mid);
    if (L<=mid) ans+=ques(L,R,l,mid,lson);
    if (R>mid) ans+=ques(L,R,mid+1,r,rson);
    return ans;
}

void Treechange(int x,int y,int k)
{
    while (top[x]!=top[y])
    {
        if (deep[top[x]]<deep[top[y]]) swap(x,y);
        change(dfn[top[x]],dfn[x],k,1,n,1);
        x=fa[top[x]];
    }
    if (deep[x]>deep[y]) swap(x,y);//记住和while中的符号不同
    change(dfn[x]+1,dfn[y],k,1,n,1);
}

int Treeques(int x,int y)
{
    int ans=0;
    while (top[x]!=top[y])
    {
        if (deep[top[x]]<deep[top[y]]) swap(x,y);
        ans+=ques(dfn[top[x]],dfn[x],1,n,1);
        x=fa[top[x]];
    }
    if (deep[x]>deep[y]) swap(x,y);
    ans+=ques(dfn[x]+1,dfn[y],1,n,1);
    return ans;
}

char opt[10];
int main()
{
//  freopen("grassplant.in","r",stdin);
//  freopen("grassplant.out","w",stdout);

    memset(head,-1,sizeof(head));
    n=read(); m=read();
    for (int i=1; i<n; i++)
    {
        int x=read(); int y=read();
        add_edge(x,y); add_edge(y,x);
    }
    dfs1(1,1,1);
    dfs2(1,1);
    for (int i=1; i<=m; i++)
    {
        scanf("%s",opt); int x=read(); int y=read();
        if (opt[0]=='P') Treechange(x,y,1);
        else printf("%d\n",Treeques(x,y));
    }
}

总结

屡败屡战

猜你喜欢

转载自blog.csdn.net/A_Comme_Amour/article/details/79782715
今日推荐