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;
}
View Code

转载于:https://www.cnblogs.com/hanyuweining/p/11057591.html

猜你喜欢

转载自blog.csdn.net/weixin_33991727/article/details/93233677