• 【CF883B】Berland Army 拓扑排序


    【CF883B】Berland Army

    题意:给出n个点,m条有向边,有的点的点权已知,其余的未知,点权都在1-k中。先希望你确定出所有点的点权,满足:

    对于所有边a->b,a的点权>b的点权
    对于i=1..k,至少有一个点的点权为i

    n,m,k<=100000

    题解:像菜肴制作一样奇怪的拓扑排序题,直接上方法吧,不会证。

    先正反跑两边拓扑排序,得出每个点点权的下界Li和上界Ri。

    将所有点按上界从小到大排序,然后枚举权值i。将所有上界为i的点都扔到堆中,再从堆里取出下界最大的那个点,将其权值赋为i。再找出所有下界为i的点,将他们的权值也都赋为i即可。

    #include <cstdio>
    #include <cstring>
    #include <utility>
    #include <queue>
    #include <vector>
    #define mp(A,B) make_pair(A,B)
    using namespace std;
    const int maxn=200010;
    typedef pair<int,int> pii;
    int n,m,k,cnt,flag;
    int to[maxn],nxt[maxn],head[maxn],pa[maxn],pb[maxn],v[maxn],L[maxn],R[maxn],d[maxn],ans[maxn];
    vector<int> p[maxn];
    vector<int>::iterator it;
    queue<int> q;
    priority_queue<pii> pq;
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    inline void add(int a,int b)
    {
    	to[cnt]=b,nxt[cnt]=head[a],head[a]=cnt++;
    }
    int main()
    {
    	n=rd(),m=rd(),k=rd();
    	int i,u;
    	for(i=1;i<=n;i++)
    	{
    		v[i]=rd();
    		if(!v[i])	L[i]=1,R[i]=k;
    		else	L[i]=R[i]=v[i];
    	}
    	memset(head,-1,sizeof(head)),cnt=0;
    	for(i=1;i<=m;i++)	pa[i]=rd(),pb[i]=rd(),d[pb[i]]++,add(pa[i],pb[i]);
    	for(i=1;i<=n;i++)	if(!d[i])	q.push(i);
    	while(!q.empty())
    	{
    		u=q.front(),q.pop();
    		for(i=head[u];i!=-1;i=nxt[i])
    		{
    			d[to[i]]--,R[to[i]]=min(R[to[i]],R[u]-1);
    			if(!d[to[i]])	q.push(to[i]);
    		}
    	}
    	for(i=1;i<=n;i++)	if(d[i])	return puts("-1"),0;
    	memset(head,-1,sizeof(head)),cnt=0;
    	for(i=1;i<=m;i++)	d[pa[i]]++,add(pb[i],pa[i]);
    	for(i=1;i<=n;i++)	if(!d[i])	q.push(i);
    	while(!q.empty())
    	{
    		u=q.front(),q.pop();
    		for(i=head[u];i!=-1;i=nxt[i])
    		{
    			d[to[i]]--,L[to[i]]=max(L[to[i]],L[u]+1);
    			if(!d[to[i]])	q.push(to[i]);
    		}
    	}
    	for(i=1;i<=n;i++)	if(d[i]||L[i]>R[i])	return puts("-1"),0;
    	for(i=1;i<=n;i++)	p[R[i]].push_back(i);
    	for(i=k;i>=1;i--)
    	{
    		for(it=p[i].begin();it!=p[i].end();it++)	pq.push(mp(L[*it],*it));
    		if(pq.empty())	return puts("-1"),0;
    		u=pq.top().second,pq.pop(),ans[u]=i;
    		while(!pq.empty())
    		{
    			u=pq.top().second;
    			if(L[u]<i)	break;
    			pq.pop(),ans[u]=i;
    		}
    	}
    	for(i=1;i<=n;i++)	printf("%d ",ans[i]);
    	return 0;
    }
  • 相关阅读:
    全面的学习资料(收藏)
    远程下载文件源码
    【转】c#托管资源和非托管资源区别
    Jquery 限制文本框输入字数
    好用的网站
    交叉表查询
    jquery 和 javascript 清空上传控件 方法总结
    关于java.io.IOException问题
    http 302
    django使用静态文件二
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8097483.html
Copyright © 2020-2023  润新知