• [CF1045A] Last chance


    题目:Last chance

    传送门:http://codeforces.com/contest/1045/problem/A

    分析:

    1)有$n$个敌方飞船,己方有$m$个武器,有三种类型。

    2)$第0种$:能攻击一艘 编号属于大小为$ki$的集合的飞船。显然,这是一个二分图最大匹配,可以暴力建边。

    3)$第1种$:能攻击一艘 编号在$[l_i,r_i]$区间内的飞船。显然,这还是二分图最大匹配,但是,“武器到区间所有飞船建边”这种复杂度就不可接受了。

    4)点与区间所有点建边可以采用线段树优化。

    5)$第2种$:能攻击三艘飞船中的0艘或者两艘,编号分别为$ai,bi,ci$。题目保证了一艘飞船至多被包括在一个这样的三元组中,也就是所有第2种武器的攻击集合互不相交。

    6)贪心攻击掉两艘。对每个三元组建一个辅助点让它们的流量和小于等于$1$.

    7)很明显的网络流了。

    8)对于$第0种$武器:源点到武器建一条容量为1的边,武器到集合中每一个飞船建一条容量为1的边。

    9)对于$第1种$武器:线段树优化点到区间建边:对于这$m$个人先建一棵线段树,父亲节点向儿子节点连容量为$INF$的边,最后叶子结点向对应的飞船连容量为$1$的边。这样给$第1种$武器对应连边的时候直接给区间连边就行了。

    10)对于第2种武器:贪心掉$a_i,b_i$,$a_i,b_i$不必向汇点连边,武器节点向$a_i,b_i$连接一条反向容量为1的边,向$c_i$连一条容量为1的边,这样就保证了$a_i,b_i,c_i$要么被选到2个,要么被选到3个。

    11)题目还要输出方案。可以采用类似退流的方式。

    代码:

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 const int maxN=200005,INF=1e9+7;
      4 int n,m,ans=0,vis[maxN];
      5 struct Edge{int to,f,next;};
      6 struct NetWorkFlow{
      7     int en,fi[maxN];
      8     Edge e[maxN];
      9     void addE(int v,int u,int f){
     10         e[++en].to=u;e[en].f=f;e[en].next=fi[v];fi[v]=en;
     11         e[++en].to=v;e[en].f=0;e[en].next=fi[u];fi[u]=en;
     12     }
     13     int tot,S,T,cnt[maxN],dis[maxN];
     14     int sap(int t,int delta){
     15         if(t==T)return delta;
     16         int sum=0,mindis=tot+1;
     17         for(int i=fi[t];i;i=e[i].next){
     18             if(e[i].f && dis[t]==dis[e[i].to]+1){
     19                 int save=sap(e[i].to,std::min(e[i].f,delta-sum));
     20                 sum+=save;
     21                 e[i].f-=save;
     22                 e[i^1].f+=save;
     23                 if(dis[S]>=tot+1 || delta==sum)return sum;
     24             }
     25             if(e[i].f && dis[e[i].to]<mindis)mindis=dis[e[i].to];
     26         }
     27         if(!sum){
     28             if(!--cnt[dis[t]])dis[S]=tot+1;
     29             else ++cnt[dis[t]=mindis+1];
     30         }
     31         return sum;
     32     } 
     33     void Sol(){
     34         cnt[0]=tot+1;
     35         while(dis[S]<tot+1)
     36             ans+=sap(S,INF);
     37     } 
     38 }NW;
     39 struct SegmentTree{
     40     int id[maxN];
     41     void Init(int v,int l,int r){
     42         id[v]=++NW.tot;
     43         if(l==r){NW.addE(id[v],l,1);return;}
     44         int mid=(l+r)>>1;
     45         Init(v<<1,l,mid);NW.addE(id[v],id[v<<1],INF);
     46         Init(v<<1|1,mid+1,r);NW.addE(id[v],id[v<<1^1],INF);    
     47     }
     48     void addE(int v,int l,int r,const int &L,const int &R,const int& u){
     49         if(L<=l && r<=R){NW.addE(u,id[v],1);return;}
     50         int mid=(l+r)>>1;
     51         if(L<=mid)addE(v<<1,l,mid,L,R,u);
     52         if(mid< R)addE(v<<1|1,mid+1,r,L,R,u);
     53     }
     54 }ST;
     55 int Re(){
     56     int ch='@',x=0;
     57     for(;ch<48 || 57<ch;ch=getchar());
     58     for(;47<ch && ch<58;ch=getchar())x=x*10+ch-48;
     59     return x;
     60 }
     61 int Beg,tmp;
     62 map<int,int>mp[maxN];
     63 void GetAns(int v){
     64     if(v>=Beg){tmp=v-Beg+1;return;}
     65     auto it=mp[v].begin();
     66     GetAns(it->first);
     67     --it->second;
     68     if(!it->second)mp[v].erase(it);
     69 }
     70 int main(){
     71     n=Re();m=Re();
     72     NW.en=1;memset(NW.fi,0,sizeof NW.fi);
     73     NW.tot=m;NW.S=++NW.tot;NW.T=++NW.tot;
     74     ST.Init(1,1,m);Beg=NW.tot+1;
     75     for(int i=1,op;i<=n;++i){
     76         ++NW.tot;
     77         op=Re();
     78         if(op==0){
     79             NW.addE(NW.S,NW.tot,1);
     80             for(int k=Re(),x;k--;){x=Re();NW.addE(NW.tot,x,1);}
     81         }else if(op==1){
     82             NW.addE(NW.S,NW.tot,1);
     83             int L=Re();int R=Re();
     84             ST.addE(1,1,m,L,R,NW.tot);
     85         }else{
     86             int a=Re();int b=Re();int c=Re();
     87             vis[a]=vis[b]=1;ans+=2;
     88             NW.addE(NW.tot,a,0);NW.e[NW.en].f=1;
     89             NW.addE(NW.tot,b,0);NW.e[NW.en].f=1;
     90             NW.addE(NW.tot,c,1);
     91         }
     92     }
     93     for(int i=1;i<=m;++i)if(!vis[i])NW.addE(i,NW.T,1);
     94     NW.Sol();
     95     printf("%d
    ",ans); 
     96     for(int i=1;i<=NW.tot;++i)
     97         for(int j=NW.fi[i];j;j=NW.e[j].next)
     98             if((j&1)&&NW.e[j].f)
     99                 mp[i][NW.e[j].to]=NW.e[j].f; 
    100     for(int i=1;i<=m;++i){
    101         bool f=true;
    102         for(int j=NW.fi[i];j&&f;j=NW.e[j].next)if(NW.e[j].to==NW.T&&NW.e[j].f)f=false;
    103         if(f){
    104             GetAns(i);
    105             printf("%d %d
    ",tmp,i);
    106         }
    107     }
    108     return 0;
    109 }
  • 相关阅读:
    分享一款日历的控件,适合新手
    解决ASP数据库连接出错,请检查连接字符串问题
    解决word中的Word experienced an error trying to open the file
    asp.net 利用jmail完成邮件的发送功能
    文章本天成 妙手偶得之 两句三年得 一吟双泪流
    有你有我有世界
    IT高薪者所具备的人格魅力
    谷歌史上10大发明精英
    坚持 乐观 方向 领悟 反思 跨越 距离
    Android之父Andy Rubin
  • 原文地址:https://www.cnblogs.com/hjj1871984569/p/10389737.html
Copyright © 2020-2023  润新知