zoukankan      html  css  js  c++  java
  • Codeforces 1045A Last chance 网络流,线段树,线段树优化建图

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF1045A.html

    题目传送们 - CF1045A

    题意

      你有 $n$ 个炮,有 $m$ 个敌人,敌人排成一列,编号从 $1$ 到 $m$ 。

      对于每门炮,可能是以下 3 种类型:

      1. 给定 $K$ ,以及一个包含 $K$ 个元素的集合,该炮最多集合内的一个敌人。保证对于所有这种类型的炮 $sum K leq 10^5$ 。

      2. 给定 $L,R$ ,该炮最多可以消灭区间 $[L,R]$ 中的一个敌人。

      3. 给定 $a,b,c$ ,该炮只能消灭集合 ${a,b,c}$ 中的 $0$ 或 $2$ 个敌人。保证所有这种类型的炮的敌人集合都不相交。

      每一个敌人最多被一个炮攻击。

      要求安排攻击方式,使得尽量多的敌人收到攻击。输出方案。

      $n,mleq 10^5$

    题解

      先扯个淡:

    挑战手残新高度1: - 1s * 3600

    挑战手残新高度2: - 1s * 2 * 3600

    这个用图片描述不方便。口述吧!

    哎呀这个网络流跑出来的结果怎么挂掉了???

    while (1){ 建图……没问题;线段树……没问题}

    都没问题啊??

    然后我就黑人问号脸了。

    忘记把和线段树同样范围的数组开成线段树范围了,虽然这个数组的取值并不影响我网络流跑出来的结果,但是炸了下标域,改变了我网络流需要涉及的数组取值。

    白白被续 2h ,真******* 难受。

    唉,我曾经天天splay LCT 时的码力已经不复存在了。

     

    kel 苟利国家生死以 kel

      做法:

      首先我们忽略掉第 3 种炮,用暴力做:

      发现就是一个裸的二分图匹配。但是第二种炮的建边太多,还是不行。

      由于第二种炮是区间建边,我们就来一个线段树优化建图就好了。

      现在考虑第三种炮。如果第三种炮的攻击个数也可以是 $1$ ,那么就好做了。

      再仔细观察,题目里说到所有第三种炮的攻击集合互不相交。这个条件必然有用啊。怎么用?

      我们把第三种炮的攻击个数限制在 $[0,2]$ 之间,然后结合之前的建图方式,跑一次网络流来匹配一下。

      这样可能会导致有些 第三种炮 的攻击了 $1$ 个人。那么显然,在他的集合里,且没有攻击的人都被攻击了,而且都是被第一或第二种炮攻击的。

      于是我们手动让他再打掉一个被“第一或第二种炮攻击的”敌人,并让原先攻击这个敌人的炮不攻击。很显然,这样不仅攻击了最多的敌人,还满足了题目限定的条件,本题就可以完成了。

      细节处理比较复杂,详细参见代码。

      时间复杂度???O(网络流) 

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef int LL;
    const int N=5005;
    int read(){
    	int x=0,f=1;
    	char ch=getchar();
    	while (!isdigit(ch)&&ch!='-')
    		ch=getchar();
    	if (ch=='-')
    		f=-1,ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	return x*f;
    }
    struct Edge{
    	int x,y,nxt,cap;
    	Edge(){}
    	Edge(int a,int b,int c,int d){
    		x=a,y=b,cap=c,nxt=d;
    	}
    };
    struct Network{
    	static const int N=20005,M=1e6,INF=0x3FFFFFFF;
    	Edge e[M];
    	int n,S,T,fst[N],cur[N],cnt;
    	int q[N],dis[N],head,tail;
    	LL MaxFlow;
    	void clear(int _n){
    		n=_n,cnt=1;
    		memset(fst,0,sizeof fst);
    	}
    	void add(int a,int b,int c){
    		e[++cnt]=Edge(a,b,c,fst[a]),fst[a]=cnt;
    		e[++cnt]=Edge(b,a,0,fst[b]),fst[b]=cnt;
    	}
    	void init(){
    		for (int i=1;i<=n;i++)
    			cur[i]=fst[i];
    	}
    	void init(int _S,int _T){
    		S=_S,T=_T,MaxFlow=0,init();
    	}
    	int bfs(){
    		memset(dis,0,sizeof dis);
    		head=tail=0;
    		q[++tail]=T,dis[T]=1;
    		while (head<tail)
    			for (int x=q[++head],i=fst[x];i;i=e[i].nxt)
    				if (!dis[e[i].y]&&e[i^1].cap){
    					if (e[i].y==T)
    						return 1;
    					dis[q[++tail]=e[i].y]=dis[x]+1;
    				}
    		return (bool)dis[S];
    	}
    	int dfs(int x,int Flow){
    		if (x==T||!Flow)
    			return Flow;
    		int now=Flow;
    		for (int &i=cur[x];i;i=e[i].nxt){
    			int y=e[i].y;
    			if (dis[x]==dis[y]+1&&e[i].cap){
    				int d=dfs(y,min(now,e[i].cap));
    				e[i].cap-=d,e[i^1].cap+=d,now-=d;
    				if (now==0)
    					break;
    			}
    		}
    		return Flow-now;
    	}
    	LL Dinic(){
    		while (bfs())
    			init(),MaxFlow+=dfs(S,INF);
    		return MaxFlow;
    	}
    	LL Auto(int _S,int _T){
    		init(_S,_T);
    		return Dinic();
    	}
    }g;
    int n,m,tot,S,T;
    int Type[N],ida[N],idsh[N],Turn[20005];
    struct Node0{vector <int> id;Node1(){id.clear();}}a0[N];
    struct Node1{vector <int> id;Node2(){id.clear();}}a1[N];
    struct Node2{int a,b,c,ia,ib,ic;}a2[N];
    struct Seg{int id,eL,eR;}t[N<<2];
    void build(int rt,int L,int R){
    	Turn[t[rt].id=++tot]=rt;
    	if (L==R)
    		return (void)(g.add(t[rt].id,idsh[L],1e6),t[rt].eL=g.cnt);
    	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    	build(ls,L,mid);
    	build(rs,mid+1,R);
    	g.add(t[rt].id,t[ls].id,1e6),t[rt].eL=g.cnt;
    	g.add(t[rt].id,t[rs].id,1e6),t[rt].eR=g.cnt;
    }
    void update(int rt,int L,int R,int xL,int xR,int id,vector <int> &ie){
    	if (xR<L||R<xL)
    		return;
    	if (xL<=L&&R<=xR)
    		return g.add(id,t[rt].id,1),ie.push_back(g.cnt);
    	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    	update(ls,L,mid,xL,xR,id,ie);
    	update(rs,mid+1,R,xL,xR,id,ie);
    }
    int find(int rt){
    	if (!t[rt].eR)
    		if (g.e[t[rt].eL].cap)
    			return g.e[t[rt].eL].cap--,(g.e[t[rt].eL].x-T);
    		else
    			return 0;
    	if (g.e[t[rt].eL].cap)
    		if (int res=find(rt<<1))
    			return g.e[t[rt].eL].cap--,res;
    	if (g.e[t[rt].eR].cap)
    		if (int res=find(rt<<1|1))
    			return g.e[t[rt].eR].cap--,res;
    	return 0;
    }
    int Match[N],Mat[2][N];
    vector <int> IDs[N<<2];
    int Get0(int i){
    	for (vector <int> :: iterator p=a0[i].id.begin();p!=a0[i].id.end();p++)
    		if (g.e[*p].cap)
    			return g.e[*p].x-T;
    	return 0;
    }
    void Get1(int i){
    	for (vector <int> :: iterator p=a1[i].id.begin();p!=a1[i].id.end();p++)
    		if (g.e[*p].cap)
    			return IDs[Turn[g.e[*p].x]].push_back(i);
    }
    void Solve_Seg(int rt){
    	while (IDs[rt].size()>0)
    		Match[find(rt)]=IDs[rt].back(),IDs[rt].pop_back();
    	if (!t[rt].eR)
    		return;
    	Solve_Seg(rt<<1);
    	Solve_Seg(rt<<1|1);
    }
    int tag[N],cc[N];
    int main(){
    	n=read(),m=read();
    	g.clear(30000);
    	tot=2,S=1,T=2;
    	for (int i=1;i<=m;i++)
    		g.add(idsh[i]=++tot,T,1);
    	build(1,1,m);
    	for (int i=1;i<=n;i++)
    		ida[i]=++tot;
    	for (int i=1;i<=n;i++){
    		Type[i]=read();
    		if (Type[i]==0){
    			int K=read();
    			g.add(S,ida[i],1);
    			for (int j=0;j<K;j++){
    				g.add(ida[i],idsh[read()],1);
    				a0[i].id.push_back(g.cnt);
    			}
    		}
    		if (Type[i]==1){
    			int L=read(),R=read();
    			g.add(S,ida[i],1);
    			update(1,1,m,L,R,ida[i],a1[i].id);
    		}
    		if (Type[i]==2){
    			g.add(S,ida[i],2);cc[i]=g.cnt;
    			g.add(ida[i],idsh[a2[i].a=read()],1),a2[i].ia=g.cnt;
    			g.add(ida[i],idsh[a2[i].b=read()],1),a2[i].ib=g.cnt;
    			g.add(ida[i],idsh[a2[i].c=read()],1),a2[i].ic=g.cnt;
    		}
    	}
    	g.n=tot;
    	int ans=g.Auto(S,T);
    	printf("%d
    ",ans);
    	memset(Match,0,sizeof Match);
    	for (int i=1;i<=n;i++){
    		if (Type[i]==0)	Match[Get0(i)]=i;
    		if (Type[i]==1)	Get1(i);
    	}
    	Solve_Seg(1);
    	for (int i=1;i<=n;i++)
    		if (Type[i]==2){
    			int cnt=Mat[0][i]=Mat[1][i]=0;
    			if (g.e[a2[i].ia].cap)Mat[cnt++][i]=g.e[a2[i].ia].x-T;
    			if (g.e[a2[i].ib].cap)Mat[cnt++][i]=g.e[a2[i].ib].x-T;
    			if (g.e[a2[i].ic].cap)Mat[cnt++][i]=g.e[a2[i].ic].x-T;
                            if (cnt==1){
                                    if (!g.e[a2[i].ia].cap)Match[a2[i].a]=0,Mat[cnt++][i]=a2[i].a;
    	                        else if (!g.e[a2[i].ib].cap)Match[a2[i].b]=0,Mat[cnt++][i]=a2[i].b;
    	                        else if (!g.e[a2[i].ic].cap)Match[a2[i].c]=0,Mat[cnt++][i]=a2[i].c;
                            }
    			Match[Mat[0][i]]=Match[Mat[1][i]]=i;
    		}
    	for (int i=1;i<=m;i++)
    		if (Match[i]!=0)
    			printf("%d %d
    ",Match[i],i);
    	return 0;
    }
    

      

  • 相关阅读:
    线段树
    数据结构<三> 队列
    数据结构<二>双向链表
    数据结构<一>单链表
    扩展欧几里德算法
    90 个 node.js 扩展模块,我们疯了
    nodejs的查询构造器
    express的路由配置优化
    express路由方案
    Redis学习笔记~目录
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/CF1045A.html
Copyright © 2011-2022 走看看