• [BZOJ4712]洪水-[树链剖分+线段树]


    Description

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

    Solution

    这道题真的是666。。

    我们设g[x]为堵住该点所有子树的和,v[x]为堵住该点的代价,则f[x]=min(g[x],v[x])。现在我们要给v[x]加上to。

    1,v[x]>=g[x],v[x]加多少都不会有影响,过;

    2,v[x]<=g[x]&&v[x]+to<=g[x],则g[fa[x]]+=to,如果f[fa[x]]改变,则还需要接着往上推。

    3,v[x]<=g[x]&&v[x]+to>g[x],则g[fa[x]]+=-v[x]+g[x],如果f[fa[x]]改变,同样需要接着往上推。

    对于情况1,直接处理掉就ok了。

    我们考虑优化情况2和3的处理。在这里我们采用树剖+线段树。线段树存储v[x]-g[x]。

    对于点x,我们沿着重链往上,如果在某条重链上都是情况2或3,直接加就好;反之在这条重链上二分。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    int n,x,y;
    ll v[200010],_g[200010],dp[200010],d;
    struct node{int y,nxt;
    }g[400010];int h[200010],tot=0;
    int m;char ch[5];
    
    int fa[200010],dep[200010],son[200010],top[200010],sz[200010];
    int cnt=0,dfn[200010],id[200010];
    
    struct XD_TREE
    {
    ll mn[800010],tag[800010];
        void build(int k,int l,int r)
        {
            if (l==r) {mn[k]=v[dfn[l]]-_g[dfn[l]];return;}
            int mid=(l+r)/2;
            build(k<<1,l,mid);build(k<<1|1,mid+1,r);
            mn[k]=min(mn[k<<1],mn[k<<1|1]);
        }
        void downtag(int k)
        {
            mn[k<<1]-=tag[k];mn[k<<1|1]-=tag[k];
            tag[k<<1]+=tag[k];tag[k<<1|1]+=tag[k];
            tag[k]=0;
        }
        int modify(int k,int l,int r,int askl,int askr,ll d)
        {
            if (l==r){
                mn[k]-=d;tag[k]+=d;
                if (mn[k]<=0) return dfn[l];
                return 0;
            }
            if (askl<=l&&r<=askr){
                if (mn[k]>d)
                {
                    mn[k]-=d;tag[k]+=d;return 0;
                }
            }
            if (tag[k]!=0) downtag(k);
            int mid=(l+r)/2,re=0;
            if (askr>mid) re=modify(k<<1|1,mid+1,r,askl,askr,d);
            if (askl<=mid&&!re) re=modify(k<<1,l,mid,askl,askr,d);
            mn[k]=min(mn[k<<1],mn[k<<1|1]);        
            return re;
        }
        ll query(int k,int l,int r,int ask)
        {
            if (l==r) return mn[k];
            if (tag[k]!=0) downtag(k);
            int mid=(l+r)/2;
            if (ask<=mid) return query(k<<1,l,mid,ask);
            else return query(k<<1|1,mid+1,r,ask);
        }
    }X;
    struct TREE_LINK//树剖 
    {
        void dfs1(int x,int f)
        {
            fa[x]=f;dep[x]=dep[f]+1;sz[x]=1;
            for(int i=h[x];i;i=g[i].nxt)
            if (g[i].y!=f) {
            dfs1(g[i].y,x);
            sz[x]+=sz[g[i].y];
            son[x]=(sz[son[x]]>=sz[g[i].y])?son[x]:g[i].y;
            _g[x]+=dp[g[i].y];
            }
            if (sz[x]>1) dp[x]=min(_g[x],v[x]);else dp[x]=v[x],_g[x]=1e9;
        }
        void dfs2(int x)
        {
            dfn[++cnt]=x;id[x]=cnt;
            top[x]=son[fa[x]]==x?top[fa[x]]:x;
            if (son[x]) dfs2(son[x]);
            for (int i=h[x];i;i=g[i].nxt)
            if (g[i].y!=fa[x]&&g[i].y!=son[x]) dfs2(g[i].y);
        }
        void work(int x,ll d)
        {
            if (!x||d<=0) return;
            while (x)
            {
                int t=X.modify(1,1,n,id[top[x]],id[x],d);
                if (t) {work(fa[t],X.query(1,1,n,id[t])+d);break;}
                x=fa[top[x]];
            }
        }
    }T;
    ll getg(int x){return v[x]-X.query(1,1,n,id[x]);}
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%lld",&v[i]);
        for (int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            g[++tot]=node{y,h[x]};h[x]=tot;
            g[++tot]=node{x,h[y]};h[y]=tot;
        }
        T.dfs1(1,0);
        T.dfs2(1);
        X.build(1,1,n);
        scanf("%d",&m);
        for (int i=1;i<=m;i++)
        {
            scanf("%s",ch);
            if (ch[0]=='Q')
            {
                scanf("%d",&x);
                ll gg=getg(x);
                printf("%lld
    ",min(gg,v[x]));
            } else
            {
                scanf("%d%lld",&x,&d);
                v[x]+=d;
                X.modify(1,1,n,id[x],id[x],-d);
                ll gg=getg(x);
                if (v[x]-d>=gg) continue;
                if (v[x]<=gg) T.work(fa[x],d);
                else T.work(fa[x],gg-v[x]+d);
            }
        }
    }
     
  • 相关阅读:
    Edit Distance编辑距离(NM tag)- sam/bam格式解读进阶
    《开讲啦》 20160910 颜宁:女科学家去哪儿了?
    pysam
    Python项目实战
    最小二乘估计法
    最大似然估计(Maximum Likelihood,ML)
    HMM隐马尔科夫模型
    贝叶斯推断|朴素贝叶斯分类|贝叶斯定理
    解决“tar:Exiting with failure status due to previous errors”【转】
    df -h执行卡住不动问题解决【转】
  • 原文地址:https://www.cnblogs.com/coco-night/p/9513890.html
Copyright © 2020-2023  润新知