CF1045A Last Chance
线段树优化建图二分图匹配w!
输出方案有点烦QAQ
大体做法:
1.对于第0种直接连上就可以啦
2.对于第1种线段树优化建图就好啦 就是建一棵线段树连进来再连出去就吼啦
3.对于第2种比较复杂 下面详细说一说
首先我们可以贪心全选第三种 因为它不重复覆盖
所以我们假定所有的第三种都是选了 a 和 b
接下来我们处理可以连到c的或者连a/b替换c
那么我们建图是这样建 当前点连a/b建反向边容量1 然后当前点连向c容量为1大概长这样
然后如果有流量到A/B我们可以替换掉C
最后输出方案 我们用map记录一下每条流量的走向 反向往回退流就可以了
还有学习到了一点map小知识 比如这样
map<int,int>::iterator it=mp.begin(); it->first; it->second;
map是键值对 所以这里的first就是键 second是值
比如说 mp[x]=y; first是x second就是y
退流的时候比较方便
//Love and Freedom. #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<queue> #include<map> #define ll long long #define inf 20021225 #define ls (x<<1) #define rs (x<<1|1) #define fa (x>>1) #define mid (l+r>>1) #define N 100010 using namespace std; struct edge{int to,lt,f;}e[N*40]; int in[N],cnt=1,tot,n,m,ss,tt; queue<int> q; int dis[N]; void add(int x,int y,int f) { //printf("%d %d %d\n",x,y,f); e[++cnt].to=y; e[cnt].lt=in[x]; e[cnt].f=f; in[x]=cnt; e[++cnt].to=x; e[cnt].lt=in[y]; e[cnt].f=0; in[y]=cnt; } bool bfs() { while(!q.empty()) q.pop(); memset(dis,0,sizeof(dis)); dis[ss]=1; q.push(ss); while(!q.empty()) { int x=q.front(); q.pop();// printf("QWQ"); for(int i=in[x];i;i=e[i].lt) { int y=e[i].to; if(e[i].f && !dis[y]) { dis[y]=dis[x]+1,q.push(y); if(y==tt) return 1; } } } return 0; } int dfs(int x,int flow) { //if(x==tt) printf("%d\n",flow); if(!flow || x==tt) return flow; int cur=flow; for(int i=in[x];i;i=e[i].lt) { int y=e[i].to; if(dis[y]==dis[x]+1 && e[i].f) { int tmp=dfs(y,min(e[i].f,cur)); if(tmp) { cur-=tmp; e[i].f-=tmp; e[i^1].f+=tmp; if(!cur) return flow; } } } dis[x]=-1; return flow-cur; } int id[N]; void build(int x,int l,int r) { id[x]=++tot; if(l==r){add(id[x],l,1); return;} build(ls,l,mid); add(id[x],id[ls],inf); build(rs,mid+1,r); add(id[x],id[rs],inf); } void link(int x,int l,int r,int LL,int RR,int v) { if(LL<=l && RR>=r){add(v,id[x],1); return;} if(LL<=mid) link(ls,l,mid,LL,RR,v); if(RR>mid) link(rs,mid+1,r,LL,RR,v); } int dinic() { int tmp=0;// printf("QWQ"); while(bfs()) tmp+=dfs(ss,inf); return tmp; } map<int,int>mp[N]; int beg; bool vis[N]; int tp; void query(int x) { if(x>beg){tp=x-beg; return;} map<int,int>::iterator it=mp[x].begin(); query(it->first); --it->second; if(!it->second) mp[x].erase(it); } int main() { int typ,l,r,x,K,k,a,b,c,ans=0; scanf("%d%d",&n,&m); tot=m; ss=++tot; build(1,1,m); beg=tot; for(int i=1;i<=n;i++) { scanf("%d",&typ); ++tot; if(typ==0) { scanf("%d",&K); while(K--) scanf("%d",&k),add(tot,k,1); add(ss,tot,1); } else if(typ==1) { scanf("%d%d",&l,&r); link(1,1,m,l,r,tot); add(ss,tot,1); } else { scanf("%d%d%d",&a,&b,&c); vis[a]=vis[b]=1; ans+=2; add(tot,a,0),e[cnt].f=1; add(tot,b,0),e[cnt].f=1; add(tot,c,1); } } tt=++tot; for(int i=1;i<=m;i++) if(!vis[i]) add(i,tt,1); ans+=dinic(); printf("%d\n",ans); for(int i=1;i<=tot;i++) for(int j=in[i];j;j=e[j].lt) if((j&1) && e[j].f) mp[i][e[j].to]=e[j].f; for(int i=1;i<=m;i++) { bool flag=1; for(int j=in[i];j&&flag;j=e[j].lt) if(e[j].to==tt&&e[j].f) flag=0; if(flag) query(i),printf("%d %d\n",tp,i); } return 0; }