bzoj4712 洪水

题目描述:

给出一棵$n(n<=200000)$的树。每个点有一个权值$w$,表示堵上这个点的花费。

$m$组操作,操作一为将点$x$的权值加上一个非负整数$d$,操作二为询问以点$x$为根的子树内堵上所有根到叶节点路径的最小花费。

题解:

设$h[x]$为$x$的所有子节点的最小花费之和。

一眼看出$dp[i]=min(w[i],h[i])$

由于每次$d$非负,我们可以发现每次只会更新$x$的$w$值,

可能更新一条链上$h$值。

于是树剖维护$dp$。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 200050
#define ll long long
inline int rd()
{
    int f=1,c=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();}
    return f*c;
}
int n,hed[N],cnt,m;
char ch[2];
struct EG
{
    int to,nxt;
}e[2*N];
void ae(int f,int t)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
int fa[N],son[N],dep[N],siz[N],top[N];
ll h[N],w[N],ff[N];
void dfs1(int u,int f)
{
    fa[u]=f;
    siz[u]=1;
    dep[u]=dep[f]+1;
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(to==f)continue;
        dfs1(to,u);
        siz[u]+=siz[to];
        h[u]+=ff[to];
        if(siz[to]>siz[son[u]])son[u]=to;
    }
    if(siz[u]==1)h[u]=0x3f3f3f3f;
    ff[u] = min(w[u],h[u]);
}
int tin[N],tim,pla[N];
void dfs2(int u,int tp)
{
    tin[u]=++tim,pla[tim]=u;
    top[u] = tp;
    if(son[u])
    {
        dfs2(son[u],tp);
        for(int j=hed[u];j;j=e[j].nxt)
        {
            int to = e[j].to;
            if(to==fa[u]||to==son[u])continue;
            dfs2(to,to);
        }
    }
}
struct segtree
{
    ll v1[N<<2],tag[N<<2];//min(w-h) h
    void add(int u,ll d)
    {
        v1[u]-=d;
        tag[u]+=d;
    }
    void pushdown(int u)
    {
        if(tag[u])
        {
            add(u<<1,tag[u]);
            add(u<<1|1,tag[u]);
            tag[u]=0;
        }
    }
    void update(int u)
    {
        v1[u] = min(v1[u<<1],v1[u<<1|1]);
    }
    void build(int l,int r,int u)
    {
        if(l==r)
        {
            v1[u] = w[pla[l]]-h[pla[l]];
            tag[u] = h[pla[l]];
            return ;
        }
        int mid = (l+r)>>1;
        build(l,mid,u<<1);
        build(mid+1,r,u<<1|1);
        update(u);
    }
    void insert(int l,int r,int u,int ql,int qr,ll d)//h+=d
    {
        if(l==ql&&r==qr)
        {
            add(u,d);
            return ;
        }
        pushdown(u);
        int mid = (l+r)>>1;
        if(qr<=mid)insert(l,mid,u<<1,ql,qr,d);
        else if(ql>mid)insert(mid+1,r,u<<1|1,ql,qr,d);
        else insert(l,mid,u<<1,ql,mid,d),insert(mid+1,r,u<<1|1,mid+1,qr,d);
        update(u);
    }
    void ins(int l,int r,int u,int qx,ll d)//w+=d
    {
        if(l==r)
        {
            v1[u]+=d;
            return ;
        }
        pushdown(u);
        int mid = (l+r)>>1;
        if(qx<=mid)ins(l,mid,u<<1,qx,d);
        else ins(mid+1,r,u<<1|1,qx,d);
        update(u);
    }
    ll query1(int l,int r,int u,int ql,int qr)//min(w-h)
    {
        if(l==ql&&r==qr)return v1[u];
        pushdown(u);
        int mid = (l+r)>>1;
        if(qr<=mid)return query1(l,mid,u<<1,ql,qr);
        else if(ql>mid)return query1(mid+1,r,u<<1|1,ql,qr);
        else return min(query1(l,mid,u<<1,ql,mid),query1(mid+1,r,u<<1|1,mid+1,qr));
    }
    ll query2(int l,int r,int u,int qx)//h
    {
        if(l==r)return tag[u];
        pushdown(u);
        int mid = (l+r)>>1;
        if(qx<=mid)return query2(l,mid,u<<1,qx);
        else return query2(mid+1,r,u<<1|1,qx);
    }
}tr;
int get_lim(int x,ll d)
{
    int l = tin[top[x]],r = tin[x],ans = l-1;
    while(l<=r)
    {
        int mid = (l+r)>>1;
        if(tr.query1(1,n,1,mid,tin[x])>=d)
        {
            r = mid-1;
        }else
        {
            ans = mid;
            l = mid+1;
        }
    }
    return pla[ans];
}
ll F(int x)
{
    return min(w[x],tr.query2(1,n,1,tin[x]));
//    return min(w[x],h[x]);
}
int main()
{
//    freopen("1.in","r",stdin);
    n=rd();
    for(int i=1;i<=n;i++)w[i] = rd();
    for(int f,t,i=1;i<n;i++)
    {
        f = rd(),t = rd();
        ae(f,t),ae(t,f);
    }
    dfs1(1,0),dfs2(1,1);
    tr.build(1,n,1);
    m = rd();
    int x,y;ll d,f0,f1;
    for(int i=1;i<=m;i++)
    {
        scanf("%s",ch);
        if(ch[0]=='Q')
        {
            x = rd();
            printf("%lld\n",F(x));
        }else
        {
            x = rd(),d = rd();
/*            f0 = F(x);
            w[x]+=d;
            f1 = F(x);
            d = f1-f0;
            x = fa[x];
            while(x&&d)
            {
                f0 = F(x);
                h[x]+=d;
                f1 = F(x);
                x = fa[x];
                d = f1-f0;
            }*/
            f0 = F(x);
            w[x]+=d;
            tr.ins(1,n,1,tin[x],d);//w+=d
            f1 = F(x);
            d = f1-f0;
            x = fa[x];
            while(x&&d)
            {
                if(tr.query1(1,n,1,tin[top[x]],tin[x])>=d)
                {
                    tr.insert(1,n,1,tin[top[x]],tin[x],d);
                    x = fa[top[x]];
                    continue;
                }
                y = get_lim(x,d);
                f0 = F(y);
                tr.insert(1,n,1,tin[y],tin[x],d);
                f1 = F(y);
                x = fa[y],d = f1-f0;
            }
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LiGuanlin1124/p/10218350.html