「6月雅礼集训 2017 Day2」C

【题目大意】

有一棵n个点的完全二叉树,边权均为1,每个点有小鸟容量c[i]

依次来了m只小鸟,第i只小鸟初始位置在pos[i]上,问来了x只小鸟的时候,怎样安排小鸟的路线可以使得小鸟移动的边权和最小,且每个点的小鸟个数不超过小鸟容量。
n,m<=3*10^5

【题解】

一眼看过去费用流

有两种方法

1. 我们对每次来小鸟都新建二分图,S->小鸟容量剩余的点,小鸟容量不够的点->T,互相连边即可。

复杂度O(n^3 + n * MinCostFlow)

2. 我们对于整棵树建一张图,每次相当于多连了一条边,跑一边spfa增广即可。

复杂度O(n * MinCostFlow)

考场写第一种啊。。qwq

那么考虑第二种,我们模拟spfa的增广过程,显然是选一条最短路来增广。

由于完全二叉树,树高log,我们可以枚举这只小鸟要迁到的点和pos的LCA,然后顺便维护子树内到这个点的最小值即可。

每次选出一条路,就把这条路上模拟退流、流边、流反向边等等操作

然后就能过了,由于完全二叉树,操作都是log的。

总复杂度O(nlogn)

# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

# define RG register
# define ST static

const int M = 3e5 + 10;
const int mod = 998244353, inf = 1e9;

int n, m, d[M], id[M], f[M][2], c[M];

# define ls (x<<1)
# define rs (x<<1|1)

inline void gs(int x) {
    d[x] = inf;
    if(c[x]) d[x] = 0, id[x] = x;
    if(ls <= n && d[ls] + (f[ls][0] ? -1 : 1) < d[x]) d[x] = d[ls] + (f[ls][0] ? -1 : 1), id[x] = id[ls];
    if(rs <= n && d[rs] + (f[rs][0] ? -1 : 1) < d[x]) d[x] = d[rs] + (f[rs][0] ? -1 : 1), id[x] = id[rs]; 
}

int main() {
//    freopen("C.in", "r", stdin);
//    freopen("C.out", "w", stdout);
    cin >> n >> m;
    for (int i=1; i<=n; ++i) scanf("%d", &c[i]);
    for (int i=n; i; --i) gs(i); 
    ll ans = 0;
    for (int i=1, x; i<=m; ++i) {
        scanf("%d", &x);
        int cnt = 0, pmi = inf, pid = 0;
        for (int par=x; par; par>>=1) {
            if(d[par] + cnt < pmi) pmi = d[par] + cnt, pid = par;
            cnt += (f[par][1] ? -1 : 1);
        }
        ans += pmi;
//        cout << "pid = " << pid << "  pmi = " << pmi << ", id = " << id[pid] << endl;
        c[id[pid]] --;
        for (int y=id[pid]; y!=pid; y>>=1) if(f[y][0]) --f[y][0]; else ++f[y][1];
        for (int y=x; y!=pid; y>>=1) if(f[y][1]) --f[y][1]; else ++f[y][0];
        for (int y=id[pid]; y!=pid; y>>=1) gs(y);
        for (int y=x; y!=pid; y>>=1) gs(y);
        for (int y=pid; y; y>>=1) gs(y);
        printf("%lld
", ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/galaxies/p/20170618_c.html