zoukankan      html  css  js  c++  java
  • 【BZOJ4383】[POI2015]Pustynia 线段树优化建图

    【BZOJ4383】[POI2015]Pustynia

    Description

    给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r,k以及接下来k个正整数,表示a[l],a[l+1],...,a[r-1],a[r]里这k个数中的任意一个都比任意一个剩下的r-l+1-k个数大(严格大于,即没有等号)。
    请任意构造出一组满足条件的方案,或者判断无解。

    Input

    第一行包含三个正整数n,s,m(1<=s<=n<=100000,1<=m<=200000)。
    接下来s行,每行包含两个正整数p[i],d[i](1<=p[i]<=n,1<=d[i]<=10^9),表示已知a[p[i]]=d[i],保证p[i]递增。
    接下来m行,每行一开始为三个正整数l[i],r[i],k[i](1<=l[i]<r[i]<=n,1<=k[i]<=r[i]-l[i]),接下来k[i]个正整数x[1],x[2],...,x[k[i]](l[i]<=x[1]<x[2]<...<x[k[i]]<=r[i]),表示这k[i]个数中的任意一个都比任意一个剩下的r[i]-l[i]+1-k[i]个数大。Σk <= 300,000

    Output

    若无解,则输出NIE。
    否则第一行输出TAK,第二行输出n个正整数,依次输出序列a中每个数。

    Sample Input

    5 2 2
    2 7
    5 3
    1 4 2 2 3
    4 5 1 4

    Sample Output

    TAK
    6 7 1000000000 6 3

    题解:这种类型的题还真是熟能生巧啊~

    我们令一条边权为1的有向边(a,b)表示Va<Vb,边权为0的有向边表示Va<=Vb。然后对于题中给出的限制条件:[l,r]中的{a1,a2,..ak}比其他数都大,我们可以从一个新建的节点u向a1,a2,...ak连边,从剩余的节点向u连边。但是剩余的节点可能很多,我们可以将它们视为k+1个区间,用线段树优化建图。

    连完边后跑一边拓扑排序就知道有没有环了,在拓扑排序的同时顺便就能求出可行方案了。

     

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #define lson (x<<1)
    #define rson (x<<1|1)
    using namespace std;
    const int maxn=1000010;
    int n,N,m,S,cnt,now;
    int to[3000000],next[3000000],val[3000000],head[maxn],v[maxn],s[maxn],p[maxn],d[maxn];
    queue<int> q;
    void add(int a,int b,int c)
    {
    	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
    	//printf("*%d %d %d
    ",a,b,c);
    }
    void build(int l,int r,int x)
    {
    	if(l==r)
    	{
    		now=max(now,x+n),v[x+n]=v[l],add(l,x+n,0);
    		return ;
    	}
    	int mid=l+r>>1;
    	add(lson+n,x+n,0),add(rson+n,x+n,0);
    	build(l,mid,lson),build(mid+1,r,rson);
    }
    void updata(int l,int r,int x,int a,int b)
    {
    	if(a>b)	return ;
    	if(a<=l&&r<=b)
    	{
    		add(x+n,now,0);
    		return ;
    	}
    	int mid=l+r>>1;
    	if(a<=mid)	updata(l,mid,lson,a,b);
    	if(b>mid)	updata(mid+1,r,rson,a,b);
    }
    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;
    }
    int main()
    {
    	//freopen("bz4383.in","r",stdin);
    	//freopen("bz4383.out","w",stdout);
    	n=rd(),S=rd(),m=rd();
    	int i,j,u,a,b,c;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<=S;i++)	a=rd(),b=rd(),v[a]=b;
    	build(1,n,1);
    	for(i=1;i<=m;i++)
    	{
    		now++,a=rd(),b=rd(),c=rd();
    		p[0]=a-1,p[c+1]=b+1;
    		for(j=1;j<=c;j++)	p[j]=rd(),add(now,p[j],1);
    		for(j=1;j<=c+1;j++)	updata(1,n,1,p[j-1]+1,p[j]-1);
    	}
    	for(i=1;i<=now;i++)	for(j=head[i];j!=-1;j=next[j])	d[to[j]]++;
    	for(i=1;i<=now;i++)	if(!d[i])	q.push(i);
    	while(!q.empty())
    	{
    		u=q.front(),q.pop();
    		if(v[u])
    		{
    			if(s[u]<=v[u])	s[u]=v[u];
    			else
    			{
    				printf("NIE");
    				return 0;
    			}
    		}
    		else	if(u<=n)	s[u]=max(s[u],1);
    		if(s[u]>1000000000)
    		{
    			printf("NIE");
    			return 0;
    		}
    		for(i=head[u];i!=-1;i=next[i])
    		{
    			s[to[i]]=max(s[to[i]],s[u]+val[i]),d[to[i]]--;
    			if(!d[to[i]])	q.push(to[i]);
    		}
    	}
    	for(i=1;i<=now;i++)	if(d[i])
    	{
    		printf("NIE");
    		return 0;
    	}
    	printf("TAK
    ");
    	for(i=1;i<n;i++)	printf("%d ",s[i]);
    	printf("%d",s[n]);
    	return 0;
    }

     

  • 相关阅读:
    redis 笔记
    经验:什么影响了数据库查询速度、什么影响了MySQL性能 (转)
    对于线程安全的一些理解
    重要的接口需要做哪些检查(转)
    数据库分库分表思路
    代码优化:Java编码技巧之高效代码50例
    java new一个对象的过程中发生了什么
    java如何防止反编译(转)
    运用加密技术保护Java源代码(转)
    redis 工具包
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7095196.html
Copyright © 2011-2022 走看看