zoukankan      html  css  js  c++  java
  • [Neerc2016]Mole Tunnels (模拟费用流)

    题目链接:http://codeforces.com/gym/101190

    SOLUTION:

    模拟费用流

    这题看完之后很容易想到费用流,但是n太大了不能直接跑。
    我们考虑模拟这个费用流的增广过程,每次多了一条S->x的容量为1,费用为0的边后,我们要找一条费用最低的x->T的路径来增广,也就是要在树上找距离x最近的一个还有食物的点。因为是完全二叉树,所以我们可以直接暴力跳父亲,维护f[x]表示x子树内有食物的点到x的距离最小值,g[x]记录这个最近点的位置。那么x->xx的距离+f[xx]就可以用来更新最近点。
    然后我们还要维护反向边的容量(因为正向边容量为inf,所以可以不维护),注意方向即可。

    然后暴力dp维护一下可能改变的点。(log n个)
    因此总的复杂度就是O(mlogn)

    原文链接:https://blog.csdn.net/Icefox_zhx/article/details/80770751

    因为找到一条路径后,路径上的反向边信息都变了,所以需要改一遍

    路径上的所有的f【x】,

    一个点的c变了,那还要给一遍从这个改变的点到root的f【x】

    CODE:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define inf 0x3f3f3f3f
    #define N 100010
    inline char gc(){
        static char buf[1<<16],*S,*T;
        if(T==S){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
        return *S++;
    }
    inline int read(){
        int x=0,f=1;char ch=gc();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
        return x*f;
    }
    int n,m,c[N],v[N][2],f[N],g[N],ans=0;//v[x][0]--x->fa[x] v[x][1]--fa[x]->x
    int main(){
      freopen("mole.in","r",stdin);
      freopen("mole.out","w",stdout);
        n=read();m=read();memset(f,inf,sizeof(f));
        for(int i=1;i<=n;++i) c[i]=read();
        for(int i=n;i>=1;--i){
            if(c[i]) f[i]=0,g[i]=i;
            if(i>>1&&f[i]+1<f[i>>1]) f[i>>1]=f[i]+1,g[i>>1]=g[i];
        }while(m--){
             int x=read(),sum=0,y,res=inf,t;
             for(int xx=x;xx;xx>>=1){
                if(f[xx]+sum<res) res=f[xx]+sum,y=g[xx],t=xx;
                sum+=v[xx][0]?-1:1;
             }ans+=res;printf("%d",ans);if(m) putchar(' ');else puts("");c[y]--;
             for(int xx=x;xx!=t;xx>>=1) v[xx][0]?v[xx][0]--:v[xx][1]++;
             for(int xx=y;xx!=t;xx>>=1) v[xx][1]?v[xx][1]--:v[xx][0]++;
             for(int xx=x;xx!=t;xx>>=1){
                f[xx]=inf;
                if(c[xx]) f[xx]=0,g[xx]=xx;
                if(xx<<1<=n&&f[xx<<1]+(v[xx<<1][1]?-1:1)<f[xx]) f[xx]=f[xx<<1]+(v[xx<<1][1]?-1:1),g[xx]=g[xx<<1];
                if((xx<<1|1)<=n&&f[xx<<1|1]+(v[xx<<1|1][1]?-1:1)<f[xx]) f[xx]=f[xx<<1|1]+(v[xx<<1|1][1]?-1:1),g[xx]=g[xx<<1|1];
             }
             for(int xx=y;xx!=t;xx>>=1){
                f[xx]=inf;
                if(c[xx]) f[xx]=0,g[xx]=xx;
                if(xx<<1<=n&&f[xx<<1]+(v[xx<<1][1]?-1:1)<f[xx]) f[xx]=f[xx<<1]+(v[xx<<1][1]?-1:1),g[xx]=g[xx<<1];
                if((xx<<1|1)<=n&&f[xx<<1|1]+(v[xx<<1|1][1]?-1:1)<f[xx]) f[xx]=f[xx<<1|1]+(v[xx<<1|1][1]?-1:1),g[xx]=g[xx<<1|1];
             }
             for(int xx=t;xx;xx>>=1){
                f[xx]=inf;
                if(c[xx]) f[xx]=0,g[xx]=xx;
                if(xx<<1<=n&&f[xx<<1]+(v[xx<<1][1]?-1:1)<f[xx]) f[xx]=f[xx<<1]+(v[xx<<1][1]?-1:1),g[xx]=g[xx<<1];
                if((xx<<1|1)<=n&&f[xx<<1|1]+(v[xx<<1|1][1]?-1:1)<f[xx]) f[xx]=f[xx<<1|1]+(v[xx<<1|1][1]?-1:1),g[xx]=g[xx<<1|1];
             }
    
    
    
        }return 0;
    }
    

      

  • 相关阅读:
    怎样去掉a标签的蓝框
    textarea中的内容的获取
    移动端rem布局
    Array的push与unshift方法性能比较分析
    浅谈移动前端性能优化(转)
    移动端高清、多屏适配方案 (转)
    js关于事件的一些总结(系列一)
    移动端实用的meta标签
    浅析js绑定同一个事件依次触发问题系列(一)
    关于移动端input框 在微信中 和ios中无法输入文字的问题
  • 原文地址:https://www.cnblogs.com/zhangbuang/p/11425195.html
Copyright © 2011-2022 走看看