Bzoj4276 [ONTAK2015]Bajtman i Okrągły Robin

来源:互联网 发布:为什么黑腾讯游戏知乎 编辑:程序博客网 时间:2024/06/07 12:23

原题网址:http://www.lydsy.com/JudgeOnline/problem.php?id=4276
一开始想在每个时间点贪心,为了正确性,加了一贯贪心的撤销操作,当当前时间点权值最大的能取的因为太晚而取不了就找一个前面能和他交换时间的互换抢劫时间,但WA掉了,然后问了神犇,他提到我这样只能一步交换,有可能连环交换,而且另一个神犇提到了网络流贪心做多半是有退流的问题。 附上WA的贪心代码:

#include<bits/stdc++.h>const int N = 5050;struct rec{int a, b, c;};rec a[N],b[N],heap[N];int n,cnt,tot,ans;bool cmp(const rec &a, const rec &b){    return a.a < b.a;}void heapup(int x){    while (x > 1 && heap[x].c > heap[x >> 1].c)        std::swap(heap[x >> 1],heap[x]),        x >>= 1;}void heapdown(int x){    while (x*2 <= cnt && heap[x*2].c > heap[x].c || x*2+1 <= cnt && heap[x*2+1].c > heap[x].c)        if (x*2+1 <= cnt && heap[x*2+1].c > heap[x*2].c)            std::swap(heap[x*2+1],heap[x]), x = x*2+1;        else            std::swap(heap[x*2],heap[x]), x = x*2;}void push(const rec &x){    heap[++cnt] = x;    heapup(cnt);}void poop(){    heap[1] = heap[cnt--];    heapdown(1);}int main(){    scanf("%d",&n);    for (int i=1; i<=n; i++)        scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].c),        a[i].b--;    std::sort(a+1,a+n+1,cmp);    int p = 1;    for (int tim=1; tim<5000; tim++){        for (; p <= n && a[p].a == tim; p++)            push(a[p]);        bool picked = 0;        for (; !picked && cnt; poop())            if (heap[1].b >= tim){                b[++tot] = heap[1];                b[tot].a = tim + 1;                ans += heap[1].c;                picked = 1;            }else                for (int i=1; i<=tot; i++)                    if (b[i].a <= tim && b[i].b >= tim){                        b[i].a = tim + 1;                        ans += heap[1].c;                        picked = 1;                        break;                    }    }    printf("%d\n",ans);    return 0;}

正解实际是费用流,实质是一个二分图最大权匹配,一边是强盗,另一边是日期,特殊的是因为匹配的是一个区间内的日期,所以可以用线段树优化建图。

#include<bits/stdc++.h>const int N = 15001;const int M = 3e5;const int INF = 1e9;struct edge{int x,y,f,v,next;} mp[M];int n,S,T,s,a,b,c,cnt,ans,first[N],q[N + 10],lc[N],rc[N],dis[N],from[N];bool inq[N];void ins(int x, int y, int f, int v){    mp[++s] = (edge){x,y,f,v,first[x]}; first[x] = s;    mp[++s] = (edge){y,x,0,-v,first[y]}; first[y] = s;}void build(int i, int l, int r){    if (l == r) {ins(i,T,1,0); return;}    ins(i,lc[i] = ++cnt,INF,0);    build(cnt,l,(l+r)/2);    ins(i,rc[i] = ++cnt,INF,0);    build(cnt,(l+r)/2+1,r);}void find(int k, int i, int l, int r, int _l, int _r){    if (l > _r || r < _l) return;    if (l >= _l && r <= _r) {ins(k,i,1,0); return;}    find(k,lc[i],l,(l+r)/2,_l,_r);    find(k,rc[i],(l+r)/2+1,r,_l,_r);}bool SPFA(){    int head = 1, tail = 2;    memset(inq,0,sizeof(inq));    for (int i=S; i<=T; i++) dis[i] = -INF;    dis[q[head] = S] = 0;    inq[q[head]] = 1;    while (head != tail){        int x = q[head++];        if (head > N) head = 1;        for (int t=first[x]; t>0; t=mp[t].next){            int y = mp[t].y;            if (mp[t].f && dis[x] + mp[t].v > dis[y]){                dis[y] = dis[x] + mp[t].v;                from[y] = t;                if (!inq[y]){                    inq[q[tail++] = y] = 1;                    if (tail > N) tail = 1;                }            }        }        inq[x] = 0;    }    return dis[T] > -INF;}void mcf(){    for (int x=T; x!=S; x=mp[from[x]].x)        mp[from[x]].f--,        mp[from[x]^1].f++;    ans += dis[T];}int main(){    scanf("%d",&n);    S = 0; T = 15000; s = 1;    build(cnt = n + 1,1,5000);    for (int i=1; i<=n; i++)        scanf("%d%d%d",&a,&b,&c),        ins(S,i,1,c),        find(i,n+1,1,5000,a,b-1);    while (SPFA()) mcf();    printf("%d\n",ans);    return 0;}
阅读全文
0 0
原创粉丝点击