zoukankan      html  css  js  c++  java
  • BZOJ4712 洪水

    这题考场上拿到了50分暴力分海星

    首先考虑暴力怎么搞,设dis[i]表示切断i节点与叶子的联系的最优价值

    tot[i]表示i节点的所有儿子的dis之和,对于叶子结点,他的tot值为0,dis为val,很容易的得到转移方程dis[i]=min(val[i],tot[i]),

    每次更新只会影响到它的父亲以及父亲往上的一条链,直到根节点,所以就可以O(hm)的解决这道题

    这是50分做法

    那50->100是质的飞越,那是DDP,当然也可以二分,但是我不会

    改变一下原先的定义,tot[i]为切断i节点与他所有轻儿子的联系

    那么转移方程改变为dis[i]=min(val[i],tot[i]+dis[son[i]])

    重儿子展开就是dis[i]=min(val[i],tot[i]+min(val[son[i]],dis[son[son[i]]]+tot[son[i]]))

    在一条重链上,一个节点的改变会影响链头的fa的tot值和所有的dis值,

    对于tot值单独在外面开一个数组维护,每次需要更新,而dis值在线段树上维护,

    如何在线段树上维护?

    对于这个东西把它转化成矩阵乘,重新定义一下矩阵乘

    乘为加,加为取min,

    构造的矩阵为2*2的,左上是0,右上是dis[i],左下是inf,右下是tot[i]。

    乘的时候是从右往左乘。

    更新的时候需要将链头的fa的tot值中链头原先的dis值,然后更新之后加上新的dis值

    对于每次询问都需要访问从链底到当前位置。

    这题有点卡常,需要用快读。

    代码如下

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #define LL long long
    #define mid ((l+r)>>1)
    #define lson k<<1,l,mid
    #define rson k<<1|1,mid+1,r
    #define ls k<<1
    #define rs k<<1|1
    #define t(rt,a,b) tr[rt].f[a][b] 
    using namespace std;
    const int N=200005;
    const LL inf=1e18;
    int n,m,cnt,head[N],fa[N],tot;
    int in[N],dep[N],top[N],dfn[N],id[N],siz[N],son[N],bot[N];
    LL vl[N],f[N],g[N];
    vector<int>q;
    struct node{
        int to,nxt;
    }e[N<<1];
    struct martix{
        LL f[2][2];
        martix(){
            f[0][0]=f[0][1]=f[1][0]=f[1][1]=0;
        }
        inline void init(){
            f[0][1]=f[1][0]=inf;
        }
        inline void mx(){
            f[0][0]=f[0][1]=f[1][0]=f[1][1]=inf;
        }
    };
    martix tr[N<<2];
    martix operator *(const martix &a,const martix &b){
        martix res;
        res.mx();
        for(int k=0;k<2;++k)
            for(int i=0;i<2;i++)
                for(int j=0;j<2;j++)
                    res.f[i][j]=min(res.f[i][j],a.f[i][k]+b.f[k][j]);
        return res;
    }
    inline int read(){
        int s=0,w=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
        return s*w;
    }
    inline void add(int from,int to){
        e[++cnt]=(node){to,head[from]};
        head[from]=cnt;in[to]++;
    }
    void dfs1(int x,int f,int deep){
        fa[x]=f;siz[x]=1;dep[x]=deep;
        int maxson=-1;
        for(int i=head[x];i;i=e[i].nxt)
            if(e[i].to!=f){
                dfs1(e[i].to,x,deep+1);
                siz[x]+=siz[e[i].to];
                if(siz[e[i].to]>maxson){
                    son[x]=e[i].to;
                    maxson=siz[e[i].to];
                }
            }
    }
    void dfs2(int x,int topf){
        f[x]=vl[x];dfn[x]=++tot;id[tot]=x;top[x]=topf;
        if(son[x]){
            dfs2(son[x],topf);
            bot[x]=bot[son[x]];
        }
        else bot[x]=x;
        for(int i=head[x];i;i=e[i].nxt){
            if(e[i].to==son[x]||e[i].to==fa[x])
                continue;
            dfs2(e[i].to,e[i].to);
            g[x]+=f[e[i].to];
        }
        if(in[x])f[x]=min(f[x],f[son[x]]+g[x]);
    }
    inline void update(int k){
        tr[k]=tr[rs]*tr[ls];
    } 
    void build(int k,int l,int r){
        if(l==r){
            t(k,1,0)=inf;
            t(k,0,1)=vl[id[l]];
            t(k,1,1)=g[id[l]];
            return ;
        }
        build(rson);build(lson);
        update(k);
    }
    martix ask(int k,int l,int r,int x,int y){
        if(x<=l&&r<=y){
            return tr[k];
        }
        martix res;
        res.init();
        if(y>mid)res=res*ask(rson,x,y);
        if(x<=mid)res=res*ask(lson,x,y);
        return res;
    }
    inline void mark_f(int x){
        while(top[x]!=1){
            martix res=ask(1,1,n,dfn[top[x]],dfn[bot[x]]);
            q.push_back(res.f[0][1]);
            x=fa[top[x]];
        }
    }
    void change(int k,int l,int r,int x){
        if(l==r&&l==x){
            t(k,0,1)=vl[id[x]];
            t(k,1,1)=g[id[x]];
            return ;
        }
        if(x<=mid)change(lson,x);
        else change(rson,x);
        update(k);
    }
    inline void chenge(int x){
        q.clear();
        mark_f(x);
        int tmp=0;
        while(top[x]!=1){
            g[fa[top[x]]]-=q[tmp++];
            change(1,1,n,dfn[x]);
            g[fa[top[x]]]+=ask(1,1,n,dfn[top[x]],dfn[bot[x]]).f[0][1];
            x=fa[top[x]];
        }
        change(1,1,n,dfn[x]);
    }
    int main(){
        n=read();
        for(int i=1;i<=n;++i)
            vl[i]=read(),in[i]=-1;
        in[1]++;
        int x,y;
        for(int i=1;i<n;++i){
            x=read();y=read();
            add(x,y);add(y,x);
        }
        dfs1(1,0,1);
        dfs2(1,1);
        build(1,1,n);
        m=read();
        char c[3];
        while(m--){
            scanf("%s%d",c+1,&x);
            if(c[1]=='Q')
                printf("%lld
    ",ask(1,1,n,dfn[x],dfn[bot[x]]).f[0][1]);
            else{
                y=read();
                vl[x]+=y;
                chenge(x);
            }
        }
        return 0;
    }
  • 相关阅读:
    CF div2 325 C
    CF div2 325 B
    CF div2 325 A
    CF div2 322 C
    CF div2 322 B
    CF div2 322 A
    Sudoku Solver POJ 2676 LightOJ 1397
    逆序数(归并排序 )
    RMQ算法
    Socket编程:listen()函数英文翻译
  • 原文地址:https://www.cnblogs.com/sanjinliushi/p/11626341.html
Copyright © 2011-2022 走看看