bzoj4712 洪水 树链剖分

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/80658433

Description


小A走到一个山脚下,准备给自己造一个小屋。这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到
山顶放了格水。于是小A面前出现了一个瀑布。作为平民的小A只好老实巴交地爬山堵水。那么问题来了:我们把这
个瀑布看成是一个n个节点的树,每个节点有权值(爬上去的代价)。小A要选择一些节点,以其权值和作为代价将
这些点删除(堵上),使得根节点与所有叶子结点不连通。问最小代价。不过到这还没结束。小A的朋友觉得这样
子太便宜小A了,于是他还会不断地修改地形,使得某个节点的权值发生变化。不过到这还没结束。小A觉得朋友做
得太绝了,于是放弃了分离所有叶子节点的方案。取而代之的是,每次他只要在某个子树中(和子树之外的点完全
无关)。于是他找到你。

n<=200000,保证任意to都为非负数

Solution


考虑没有修改的情况,设f[i]表示以i为根的子树不能通向叶节点最小代价,h[i]=Σf[son[i]],w[i]为去掉节点i的代价,那么f[i]=min(h[i],w[i])
加上修改操作,我们增大节点i的w会影响fa[i]当且仅当h[fa[i]]+delta

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

typedef long long LL;
const LL INF=1e15;
const int N=200005;
const int E=400005;

struct edge {int x,y,next;} e[E];

LL mn[N<<2],tag[N<<2],w[N],h[N],f[N];
int fa[N],bl[N],dep[N],size[N];
int pos[N],dfn[N];
int ls[N],edCnt;

LL read() {
    LL x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void add_edge(int x,int y) {
    e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
    e[++edCnt]=(edge) {y,x,ls[y]}; ls[y]=edCnt;
}

void dfs1(int now) {
    size[now]=1;
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y==fa[now]) continue;
        dep[e[i].y]=dep[now]+1;
        fa[e[i].y]=now;
        dfs1(e[i].y);
        size[now]+=size[e[i].y];
        h[now]+=f[e[i].y];
    }
    if (size[now]==1) h[now]=INF;
    f[now]=std:: min(w[now],h[now]);
}

void dfs2(int now,int up) {
    pos[now]=++pos[0]; bl[now]=up;
    dfn[pos[now]]=now;
    int mx=0;
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y!=fa[now]&&size[e[i].y]>size[mx]) mx=e[i].y;
    }
    if (!mx) return ;
    dfs2(mx,up);
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y!=fa[now]&&e[i].y!=mx) dfs2(e[i].y,e[i].y);
    }
}

void push_down(int now) {
    if (!tag[now]) return ;
    tag[now<<1]+=tag[now]; tag[now<<1|1]+=tag[now];
    mn[now<<1]-=tag[now]; mn[now<<1|1]-=tag[now];
    tag[now]=0;
}

LL get_h(int now,int tl,int tr,int x) {
    if (tl!=tr) push_down(now);
    if (tl==tr) {
        mn[now]=w[dfn[tl]]-tag[now];
        return tag[now];
    }
    LL ret; int mid=(tl+tr)>>1;
    if (x<=mid) ret=get_h(now<<1,tl,mid,x);
    else ret=get_h(now<<1|1,mid+1,tr,x);
    mn[now]=std:: min(mn[now<<1],mn[now<<1|1]);
    return ret;
}

int modify(int now,int tl,int tr,int l,int r,LL v) {
    if (tl!=tr) push_down(now);
    int mid=(tl+tr)>>1,ret;
    if (tl==l&&tr==r) {
        if (mn[now]>=v) {
            tag[now]+=v; mn[now]-=v;
            return 0;
        } else if (l==r) {
            tag[now]+=v; mn[now]-=v;
            return dfn[l];
        }
        ret=modify(now<<1|1,mid+1,tr,mid+1,r,v);
        if (!ret) ret=modify(now<<1,tl,mid,l,mid,v);
        mn[now]=std:: min(mn[now<<1],mn[now<<1|1]);
        return ret;
    }
    if (r<=mid) {
        ret=modify(now<<1,tl,mid,l,r,v);
    } else if (l>mid) {
        ret=modify(now<<1|1,mid+1,tr,l,r,v);
    } else {
        ret=modify(now<<1|1,mid+1,tr,mid+1,r,v);
        if (!ret) ret=modify(now<<1,tl,mid,l,mid,v);
    }
    mn[now]=std:: min(mn[now<<1],mn[now<<1|1]);
    return ret;
}

void build(int now,int tl,int tr) {
    if (tl==tr) {
        int x=dfn[tl];
        tag[now]=h[x];
        mn[now]=w[x]-h[x];
        return ;
    }
    int mid=(tl+tr)>>1;
    build(now<<1,tl,mid);
    build(now<<1|1,mid+1,tr);
    mn[now]=std:: min(mn[now<<1],mn[now<<1|1]);
}

void change(int x,LL v) {
    if (v<=0) return ;
    int ret=0;
    while (x) {
        ret=modify(1,1,pos[0],pos[bl[x]],pos[x],v);
        if (ret) break;
        x=fa[bl[x]];
    }
    if (ret) change(fa[ret],w[ret]-get_h(1,1,pos[0],pos[ret])+v);
}

int main(void) {
    int n=read();
    rep(i,1,n) w[i]=read();
    rep(i,2,n) add_edge(read(),read());
    dep[1]=1; dfs1(1); dfs2(1,1);
    build(1,1,n);
    for (int T=read();T--;) {
        char opt[2]; scanf("%s",opt);
        if (opt[0]=='Q') {
            int x=read();
            LL ans=std:: min(get_h(1,1,n,pos[x]),w[x]);
            printf("%lld\n", ans);
        } else if (opt[0]=='C') {
            int x=read(); LL y=read();
            w[x]+=y; LL h=get_h(1,1,n,pos[x]);
            if (w[x]-y<h) change(fa[x],std:: min(h,w[x])-std:: min(h,w[x]-y));
        }
    }
    return 0;
}
阅读更多

没有更多推荐了,返回首页