[bzoj4849]Mole Tunnels

来源:互联网 发布:Java凸包算法 编辑:程序博客网 时间:2024/06/06 16:26

题目描述

鼹鼠们在底下开凿了n个洞,由n-1条隧道连接,对于任意的i>1,第i个洞都会和第i/2(取下整)个洞间有一条隧
道,第i个洞内还有ci个食物能供最多ci只鼹鼠吃。一共有m只鼹鼠,第i只鼹鼠住在第pi个洞内,一天早晨,前k只
鼹鼠醒来了,而后n-k只鼹鼠均在睡觉,前k只鼹鼠就开始觅食,最终他们都会到达某一个洞,使得所有洞的ci均大
于等于该洞内醒着的鼹鼠个数,而且要求鼹鼠行动路径总长度最小。现对于所有的1<=k<=m,输出最小的鼹鼠行动
路径的总长度,保证一定存在某种合法方案。

做法

费用流模型显然。
树高是log n,而且每个点只有两个儿子 。
很容易模拟。

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=300000+10,inf=1000000000;struct dong{    int x,y;} L[maxn],R[maxn],S[maxn];int p[maxn],c[maxn],a[maxn];int i,j,k,l,t,n,m,wdc,xdl,num,ans;bool czy,gjx;int read(){    int x=0,f=1;    char ch=getchar();    while (ch<'0'||ch>'9'){        if (ch=='-') f=-1;        ch=getchar();    }    while (ch>='0'&&ch<='9'){        x=x*10+ch-'0';        ch=getchar();    }    return x*f;}void update(int x){    L[x].y=R[x].y=S[x].y=inf;    int t;    if (x*2<=n){        R[x].x=S[x*2].x;        if (a[x*2]>=0) t=1;else t=-1;        R[x].y=S[x*2].y+t;    }    if (x*2+1<=n){        L[x].x=S[x*2+1].x;        if (a[x*2+1]>=0) t=1;else t=-1;        L[x].y=S[x*2+1].y+t;    }    if (c[x]>0&&L[x].y>0){        L[x].x=x;        L[x].y=0;    }    if (c[x]>0&&R[x].y>0){        R[x].x=x;        R[x].y=0;    }    if (L[x].y<S[x].y) S[x]=L[x];    if (R[x].y<S[x].y) S[x]=R[x];}void dfs(int x){    if (x>n) return;    dfs(x*2);    dfs(x*2+1);    update(x);}void updata(int x){    if (!x) return;    update(x);    updata(x/2);}void work(int x){    int y=x;    wdc=S[x].x;num=S[x].y;    czy=1;    t=0;    while (x>1){        if (a[x]<=0) t+=1;else t-=1;        if (x%2==0) gjx=1;else gjx=0;        x/=2;        if (gjx){            if (L[x].y+t<num){                num=L[x].y+t;                wdc=L[x].x;                czy=0;                xdl=x;            }        }        else{            if (R[x].y+t<num){                num=R[x].y+t;                wdc=R[x].x;                czy=0;                xdl=x;            }        }    }    ans+=num;    x=y;    c[wdc]--;    if (czy){        y=wdc;        while (y!=x){            a[y]++;            y/=2;        }        updata(wdc);    }    else{        y=x;        while (y!=xdl){            a[y]--;            y/=2;        }        y=wdc;        while (y!=xdl){            a[y]++;            y/=2;        }        updata(x);        updata(wdc);    }}int main(){    freopen("c.in","r",stdin);freopen("c.out","w",stdout);    n=read();m=read();    fo(i,1,n) c[i]=read();    fo(i,1,m) p[i]=read();    dfs(1);    fo(i,1,m){        work(p[i]);        printf("%d ",ans);    }}
原创粉丝点击