码迷,mamicode.com
首页 > 其他好文 > 详细

[CF1045A] Last chance

时间:2019-02-17 00:46:00      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:子节点   namespace   ons   ble   max   最大   its   oid   void   

题目: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\n",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\n",tmp,i);
106         }
107     }
108     return 0;
109 }

 

[CF1045A] Last chance

标签:子节点   namespace   ons   ble   max   最大   its   oid   void   

原文地址:https://www.cnblogs.com/hjj1871984569/p/10389737.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!