题目: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 }