CodeForces 1045A. Last chance(线段树+网络流SAP)

网络流,对三种武器分别有不同建图的方法,核心宗旨是:源点->武器->飞船->汇点。

  • SQL rockets – every SQL rocket can destroy at most one spaceship in the given set.
  • Cognition beams – every Cognition beam has an interval [l,r],and can destroy at most one spaceship in that interval.
  • OMG bazooka – every OMG bazooka has three possible targets, however, each bazooka can destroy either zero or exactly two spaceships. In addition, due to the smart targeting system, the sets of the three possible targets of any two different OMG bazookas are disjoint (that means that every ship is targeted with at most one OMG bazooka).

因为题目种对三种武器做了如下规定:

1.SQL rockets:ΣK <=100000,可以直接建图。

2.[l,r]中挑一个毁灭,则可以用线段树建图。

3.所有的OMG bazooka能销毁的目标集合之间互不相交,只能摧毁两个或者不摧毁。则由贪心策略得到摧毁最多舰船时所有的bazooka一定会被使用。

证明:假设最优状态下有一枚bazooka x无法使用;则x所能摧毁的集合中有两个或者三个被别的武器所摧毁,一共消耗了两个或者三个;在使用x后,有武器多余出来被用来摧毁别的目标,则不使用x的最优状态不是最优状态(没有未来的未来不是我想要的未来);

确定使用贪心后,就先把bazooka消灭的武器数量添加上,在这个节点稍微操作一下就好;

仔(can)细(kao)思(ti)考(jie)后,得到了如下的代码:

#include<bits/stdc++.h>
#define N 200005
#define inf 0x3f3f3f3f
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mid ((l+r)>>1)
typedef unsigned int __Index;
__Index tot;
__Index id[N],Begin;
int cnt,head[N],cur_edge[N],pre[N];
bool vis[N];
struct Edge{
    int v,cap,next;
}edge[N];
inline void __add(__Index a,__Index b,int c){
    edge[++cnt].v = b;
    edge[cnt].cap = c;
    edge[cnt].next = head[a];
    head[a] = cnt;
}
void add(__Index a,__Index b,int c){
    __add(a,b,c);
    __add(b,a,0);
}
void build(__Index l,__Index r,__Index rt){
    id[rt]=++tot;
    if(l==r){
        add(id[rt],l,1);
        return;
    }
    build(l,mid,lson);
    build(mid+1,r,rson);
    add(id[rt],id[lson],inf);
    add(id[rt],id[rson],inf);
}
void upDate(__Index L,__Index R,__Index l,__Index r,__Index rt) {
    if (L <= l and r <= R) {
        add(tot, id[rt], 1);
        return;
    }
    if (R <= mid)upDate(L, R, l, mid, lson);
    else if (L > mid)upDate(L, R, mid + 1, r, rson);
    else {
        upDate(L, mid, l, mid, lson);
        upDate(mid+1,R,mid+1,r,rson);
    }
}
__Index _n,m,src,dst,n;
int d[N],numd[N];
using namespace std;
void Bfs(int sink){
    memset(numd,0,sizeof(numd));
    fill(d+1,d+1+n,n);
    numd[n] = n;
    d[sink] = 0;
    --numd[n],++numd[0];
    queue<int>Q;
    Q.push(sink);
    while(!Q.empty()){
        int v = Q.front();
        Q.pop();
        for(int i = head[v] ,u; ~i ; i = edge[i].next){
            u = edge[i].v;
            if(d[u] < n )continue;
            d[u] = d[v]+1;
            --numd[n];
            ++numd[d[u]];
            Q.push(u);
        }
    }
}
int SAP(__Index source,__Index sink){
    memcpy(cur_edge,head,(n+1)*sizeof(int));
    int max_flow = 0;
    Bfs(sink);
    int u = source,neck = 0;
    while (d[source] < n){
        if(u==sink){
            int cur_flow = inf;
            for(int from = source ; from!=sink;from = edge[cur_edge[from]].v){
                if(cur_flow>edge[cur_edge[from]].cap){
                    neck = (__Index)from;
                    cur_flow = edge[cur_edge[from]].cap;
                }
            }
            for(int from=source; from!=sink; from=edge[cur_edge[from]].v){
                int tmp=cur_edge[from];
                edge[tmp].cap-=cur_flow;
                edge[tmp^1].cap+=cur_flow;
            }
            max_flow+=cur_flow;//累加计算最大流
            u=neck;
        }
        int i;
        for(i = cur_edge[u] ; ~i ; i = edge[i].next){
            if(edge[i].cap and d[u] == d[edge[i].v]+1)break;
        }
        if(-1!=i){
            cur_edge[u] = i;
            pre[edge[i].v] = u;
            u = edge[i].v;
        }
        else{
            --numd[d[u]];
            if(!numd[d[u]])break;
            cur_edge[u] = head[u];
            int tmp = n;
            for(int j = head[u] ; ~j ; j = edge[j].next){
                if(edge[j].cap and tmp > d[edge[j].v]){
                    tmp = d[edge[j].v];
                }
            }
            d[u] = tmp+1;
            numd[d[u]]++;
            if(u!=source)u = pre[u];
        }
    }
    return max_flow;
}

void init(){
    memset(head,-1, sizeof(head));
    tot = m;
    cnt = -1;
    src = ++tot;
    build(1,m,1);
    Begin = tot;
}
int tmp = 0;
map<int,int>mp[N];
void Query(int p){
    if( p > Begin){
        tmp = p-Begin;
        return;
    }
    auto it = mp[p].begin();
    Query(it->first);
    --it->second;
    if(!it->second)mp[p].erase(it);
}
int main(){
    ios::sync_with_stdio(false);
    cin>>_n>>m;
    init();
    int k,op,ans = 0;
    __Index sp,l,r,c;
    for(int i = 0 ; i < _n ; ++i){
        ++tot;
        cin>>op;
        switch (op){
            case 0:
                cin>>k;
                while (k--){
                    cin>>sp;
                    add(tot,sp,1);
                }
                add(src,tot,1);
                break;
            case 1:
                cin>>l>>r;
                upDate(l,r,1,m,1);
                add(src,tot,1);
                break;
            default:
                cin>>l>>r>>c;
                add(tot,l,0);
                edge[cnt].cap = 1;
                add(tot,r,0);
                edge[cnt].cap = 1;
                add(tot,c,1);
                vis[l] = vis[r] = true;
                ans+=2;
                break;
        }
    }
    dst = ++tot;
    for(__Index i = 1 ; i <= m ; ++i){
        if(!vis[i])add(i,dst,1);
    }
    n = tot;
    ans+=SAP(src,dst);
    for(int i=1;i<=tot;++i){
        for(int j = head[i] ; ~j  ; j = edge[j].next){
            if((j&1)and edge[j].cap){
                mp[i][edge[j].v] = edge[j].cap;
            }
        }
    }
    cout<<ans<<"
";
    for(int i = 1 ; i <=  m ; ++i){
        bool f = true;
        for(int j = head[i] ; (~j) and f ; j = edge[j].next){
            if(edge[j].v == dst and edge[j].cap==1)f = false;
        }
        if(f){
            Query(i);
            cout<<tmp<<" "<<i<<"
";
        }
    }
}
原文地址:https://www.cnblogs.com/DevilInChina/p/9856219.html