bzoj3218 a + b Problem

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3218

【题解】

按照最小割建模,S->x连流量为white的边,x->T连流量为black的边,割掉S->x表示取黑色,割掉x->T表示取白色,一开始加上所有贡献。

考虑奇怪的格子,一定是对于点对$(x,y)$,$x$选了黑,$y$选了白,且$y$满足条件,才会扣除$p_i$的贡献。

暴力的想法,枚举每一对$(x,y)$关系,连边y->x,流量$p_i$。

我们发现上面的做法有些问题,就是如果$x$是奇怪的点,且和很多白点有关系,其实会被算了很多次。

这个问题好办,我们把每个点$x$多建一个$x‘$,从$i‘$向$x$连边,流量为$p_i$。

从$j$向$i‘$连边,流量为$+\infty$,表示这条边不能被割。

我们建完图,发现,卡空间。。。

那怎么办啊?

发现奇怪的点的关系其实是一个二维限制,可以用主席树来求出,可是求出没有什么用,边还是很多,考虑把这棵主席树全部放到建的网络流图里。

主席树的$root_i$的区间$[l,r]$表示$a_j$在$[l,r]$内,且$j < i$的点。

那么每次我们主席树只会新加一条链,我们把这条链自下而上连边,主席树上的边流量均为$+\infty$,表示不能割掉

那么对于每个底层区间$[p, p]$,如果有$a_j$在$p$中,连边j->这个区间的id。

当然这样可能每个底层区间有一坨,那么就从主席树的$rt_{i-1}$的这个地方向$rt_i$的这个地方连边即可。

每次加入点前,先查询区间$[l_i,r_i]$,把区间$[l_i,r_i]$的$O(logn)$个代表节点拉出来,跟$i‘$连边。

这样边数就在n*log级别,可以承受。

空间开的时候稍微注意点即可。

# include <queue>
# include <vector>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N = 5e3 + 10, M = 1.5e6 + 10;
const int mod = 1e9+7, inf = 1e9;
const int Ms = 3e6 + 5;

int n;
vector<int> ps;
struct pa {
    int a, b, w, l, r, p;
    pa() {}
    pa(int a, int b, int w, int l, int r, int p) : a(a), b(b), w(w), l(l), r(r), p(p) {}
}p[N];

int idx = 0, S, T;
int head[M], nxt[M], to[M], tot = 1, flow[M];
inline void add(int u, int v, int fl) {
    ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; flow[tot] = fl;
}
inline void adde(int u, int v, int fl) {
//    printf("%d ---> %d, flow = %d\n\n", u, v, fl);
    add(u, v, fl); add(v, u, 0);
}

int rt[N], id[N];
struct CMT {
    int ch[Ms][2], id[Ms], siz;
    inline void set() {
        siz = 0;
        memset(ch, 0, sizeof ch);
        memset(id, 0, sizeof id);
    }
    inline void edt(int &x, int y, int l, int r, int d, int lk) {
        x = ++siz, id[x] = ++idx;
        ch[x][0] = ch[y][0], ch[x][1] = ch[y][1];
        if(l == r) {
            adde(lk, id[x], inf);
            if(y) adde(id[y], id[x], inf);
            return ;
        }
        int mid = l+r>>1;
        if(d <= mid) edt(ch[x][0], ch[y][0], l, mid, d, lk);
        else edt(ch[x][1], ch[y][1], mid+1, r, d, lk);
        if(ch[x][0]) adde(id[ch[x][0]], id[x], inf);
        if(ch[x][1]) adde(id[ch[x][1]], id[x], inf);
    }
    inline void link(int x, int l, int r, int L, int R, int lk) {
        if(!x) return ;
        if(L <= l && r <= R) {
            adde(id[x], lk, inf);
            return ;
        }
        int mid = l+r>>1;
        if(L <= mid) link(ch[x][0], l, mid, L, R, lk);
        if(R > mid) link(ch[x][1], mid+1, r, L, R, lk);
    }
}t;

namespace MF {
    queue<int> q;
    int c[M], cur[M];
    inline bool bfs() {
        while(!q.empty()) q.pop();
        for (int i=1; i<=idx; ++i) c[i] = -1;
        q.push(S); c[S] = 1;
        while(!q.empty()) {
            int top = q.front(); q.pop();
            for (int i=head[top]; i; i=nxt[i]) {
                if(c[to[i]] != -1 || !flow[i]) continue;
                c[to[i]] = c[top] + 1;
                q.push(to[i]);
                if(to[i] == T) return 1;
            }
        }
        return 0;
    }
    inline int dfs(int x, int low) {
        if(x == T) return low;
        int r = low, fl;
        for (int i=cur[x]; i; i=nxt[i]) {
            if(c[to[i]] != c[x] + 1 || !flow[i]) continue;
            fl = dfs(to[i], min(r, flow[i]));
            flow[i] -= fl; flow[i^1] += fl; r -= fl;
            if(flow[i] > 0) cur[x] = i;
            if(!r) return low;
        }
        if(low == r) c[x] = -1;
        return low-r;
    }
    inline int main() {
        int ret = 0;
        while(bfs()) {
            for (int i=1; i<=idx; ++i) cur[i] = head[i];
            ret += dfs(S, inf);
        }
        return ret;
    }
}

int main() {
    int sum = 0;
    scanf("%d", &n);
    S = n+n+1, T = n+n+2;
    for (int i=1; i<=n; ++i) {
        scanf("%d%d%d%d%d%d", &p[i].a, &p[i].b, &p[i].w, &p[i].l, &p[i].r, &p[i].p);
        ps.push_back(p[i].a), ps.push_back(p[i].l), ps.push_back(p[i].r);
        adde(S, i, p[i].w); adde(i, T, p[i].b);
        adde(i+n, i, p[i].p);
        sum = sum + p[i].w + p[i].b;
    }
    sort(ps.begin(), ps.end()); ps.erase(unique(ps.begin(), ps.end()), ps.end());
    for (int i=1; i<=n; ++i) {
        p[i].a = lower_bound(ps.begin(), ps.end(), p[i].a) - ps.begin() + 1;
        p[i].l = lower_bound(ps.begin(), ps.end(), p[i].l) - ps.begin() + 1;
        p[i].r = lower_bound(ps.begin(), ps.end(), p[i].r) - ps.begin() + 1;
    }
    idx = n+n+2; t.set();
    for (int i=1; i<=n; ++i) {
        t.link(rt[i-1], 1, ps.size(), p[i].l, p[i].r, i+n);
        t.edt(rt[i], rt[i-1], 1, ps.size(), p[i].a, i);
    }
    cout << sum - MF::main();
    return 0;
}

时间: 2024-10-10 09:46:00

bzoj3218 a + b Problem的相关文章

[bzoj3218] a+b problem [最小割+数据结构优化建图]

题面 传送门 思路 最小割 我们首先忽略掉那个奇♂怪的限制,就有一个比较显然的最小割模型: 建立源点$S$和汇点$T$ 对于每个元素$i$建立一个点$i$,连边$<S,i,w[i]>$和$<i,T,b[i]>$ 这样,割掉$<S,i>$边就表示选白色,割掉$<i,T>$边就表示选黑色,那么答案就是$\sum_{i=1}^nb[i]+w[i] - mincut$ 但是现在有一个奇♂怪的限制出来了 奇♂怪的限制 这个限制,是当$i$点黑色,$j<i$点白色

A Math Problem

A Math Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 237    Accepted Submission(s): 117 Problem Description You are given a positive integer n, please count how many positive integers

Water Problem

water problem 发布时间: 2015年10月10日 15:34   时间限制: 1000ms   内存限制: 256M 描述 题意很简单 给你N个数, Q个查询 每次查询给你一个区间[L, R] 你要找出 [L, R] 这个区间里面取模M后的最大值. 输入 第一行一个T,表示测试数据组数.第二行两个整数N, M (1<=N<=10^5, 1<=M<=10^9).第三行给你N个整数 整数范围在1到10^9之间.第四行给你一个整数Q. ( 1<=Q<=10^5)

FOJ Problem 2261 浪里个浪

                                                                                                                                                           Problem 2261 浪里个浪 Accept: 40    Submit: 106Time Limit: 1500 mSec    Memory Limit : 32768 KB Pro

XJTUOJ wmq的A&#215;B Problem FFT

wmq的A×B Problem 发布时间: 2017年4月9日 17:06   最后更新: 2017年4月9日 17:07   时间限制: 3000ms   内存限制: 512M 描述 这是一个非常简单的问题. wmq如今开始学习乘法了!他为了训练自己的乘法计算能力,写出了n个整数,并且对每两个数a,b都求出了它们的乘积a×b.现在他想知道,在求出的n(n−1)2个乘积中,除以给定的质数m余数为k(0≤k<m)的有多少个. 输入 第一行为测试数据的组数. 对于每组测试数据,第一行为2个正整数n,

hidden node and exposed node problem

Exposed node problem In wireless networks, theexposed node problem occurs when a node is prevented from sending packets to other nodes because of a neighboring transmitter. Consider an example of 4 nodes labeled R1, S1, S2, and R2, where the two rece

南阳524 A-B Problem

A-B Problem 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 A+B问题早已经被大家所熟知了,是不是很无聊呢?现在大家来做一下A-B吧. 现在有两个实数A和B,聪明的你,能不能判断出A-B的值是否等于0呢? 输入 有多组测试数据.每组数据包括两行,分别代表A和B. 它们的位数小于100,且每个数字前中可能包含+,- 号. 每个数字前面和后面都可能有多余的0. 每组测试数据后有一空行. 输出 对于每组数据,输出一行. 如果A-B=0,输出YES,否则输出NO

Lab 1: Write a java program for the triangle problem and test the program with Junit.

Tasks: 1. Install Junit(4.12), Hamcrest(1.3) with Eclipse 将两个jar包添加到工程中 2. Install Eclemma with Eclipse 3. Write a java program for the triangle problem and test the program with Junit. [Description of triangle problem]Function triangle takes three i

HDU 1016 Prime Ring Problem(DFS)

题目链接 Problem Description A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime. Note: the number of first circle should always