其他分享
首页 > 其他分享> > BZOJ 4849 [NEERC2016] Mole Tunnels (模拟费用流)

BZOJ 4849 [NEERC2016] Mole Tunnels (模拟费用流)

作者:互联网

题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=4849

题解

其实也是模拟费用流,但是这道题和一般的题目不一样,这道题是在一个完全二叉树上
这意味着我们根本不需要考虑什么类似数轴上老鼠进洞之类的做法,我们跑费用流,每次选一条最短路增广即可
然后增广之后最短路上的点费用会由\(1\)变成\(-1\), 直接在完全二叉树上暴力修改暴力维护子树内最近的食物点即可
说白了就是暴力,但是复杂度\(O(n\log n)\).


代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iostream>
using namespace std;
 
inline int read()
{
    int x=0; bool f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
    if(f) return x;
    return -x;
}

const int N = 1e5;
const int INF = 1e8;
struct Element
{
    int x,pos;
    Element() {}
    Element(int _x,int _pos) {x = _x,pos = _pos;}
};
void update(Element &x,Element y) {if(y.x<x.x) x = y;}
Element dp[N+3];
int w[N+3];
int pos[N+3];
int dep[N+3];
int c[N+3];
int n,m;
 
int LCA(int u,int v)
{
    while(u!=v)
    {
        if(u>v) u>>=1;
        else v>>=1;
    }
    return u;
}

void pushup(int u)
{
    if(w[u]>0) {dp[u] = Element(0,u);}
    else {dp[u] = Element(INF,0);}
    if((u<<1)<=n) {update(dp[u],Element(dp[u<<1].x+(c[u<<1]<0?-1:1),dp[u<<1].pos));}
    if((u<<1|1)<=n) {update(dp[u],Element(dp[u<<1|1].x+(c[u<<1|1]<0?-1:1),dp[u<<1|1].pos));}
//  printf("pushup dp[%d]=(%d,%d)\n",u,dp[u].x,dp[u].pos);
}
 
Element query(int u)
{
    Element ret(INF,0); int tmp = 0;
    while(u)
    {
        update(ret,Element(dp[u].x+tmp,dp[u].pos));
        tmp += c[u]>0?-1:1;
        u>>=1;
    }
    return ret;
}
 
void addval(int u,int v,int x)
{
    while(u!=v)
    {
        c[u] += x;
        pushup(u>>1);
        u>>=1;
    }
    while(u>0)
    {
        pushup(u);
        u>>=1;
    }
}
 
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++) scanf("%d",&w[i]);
    for(int i=1; i<=m; i++) scanf("%d",&pos[i]);
    dep[1] = 1; for(int i=2; i<=n; i++) dep[i] = dep[i>>1]+1;
    for(int i=n; i>=1; i--) pushup(i);
    int ans = 0;
    for(int i=1; i<=m; i++)
    {
        int u = pos[i];
        Element tmp = query(u);
        ans += tmp.x; int v = tmp.pos,lca = LCA(u,v);
        w[v]--; pushup(v);
        addval(u,lca,-1);
        addval(v,lca,1);
        printf("%d ",ans);
    }
    return 0;
}

标签:费用,NEERC2016,int,getchar,4849,二叉树,include,Tunnels,pushup
来源: https://www.cnblogs.com/suncongbo/p/11346415.html