zoukankan      html  css  js  c++  java
  • [POI2015]Pustynia

    [POI2015]Pustynia

    题目大意:

    给定一个长度为(n(nle10^5))的正整数序列(a),每个数都在(1)(10^9)范围内,告诉你其中(s)个数,并给出(m)条信息,每条信息包含三个数(l,r,k)以及接下来(k(sum kle3 imes10^5))个正整数,表示(a_{lsim r})里这(k)个数中的任意一个都严格大于剩下(r-l+1-k)个数中的任意一个数。

    请任意构造出一组满足条件的方案,或者判断无解。

    思路:

    考虑差分约束,若一个点(u)大于另一个点(v),则连一条从(v)(u)的新边。若存在环则说明无解,否则在DAG上DP即可。

    但是直接暴力连边时空复杂度都不对,因此我们可以考虑拆点,将(r-l+1-k)个点全部连向一个新的点(t),边权为(0),在从(t)连向(k)个新点,边权为(1)。这样虽然比前面的暴力做法优,但还是不能通过这道题目。

    由于我们要连的(r-l+1-k)个点中,有许多点都是相邻的,因此我们可以将这些点拆成至多(k+1)个区间,用线段树优化连边即可。

    源代码:

    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<algorithm>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int N=1e5+1,lim=1e9,V=5e5+1;
    struct Edge {
    	int to,w;
    };
    std::vector<Edge> e[V];
    bool vis[V];
    int ind[V],d[V],dis[V],tot;
    inline void add_edge(const int &u,const int &v,const int &w) {
    	e[u].push_back((Edge){v,w});
    	ind[v]++;
    }
    class SegmentTree {
    	#define _left <<1
    	#define _right <<1|1
    	#define mid ((b+e)>>1)
    	private:
    		int id[V<<2];
    	public:
    		void build(const int &p,const int &b,const int &e) {
    			if(b==e) {
    				id[p]=b;
    				return;
    			}
    			id[p]=++tot;
    			build(p _left,b,mid);
    			build(p _right,mid+1,e);
    			add_edge(id[p _left],id[p],0);
    			add_edge(id[p _right],id[p],0);
    		}
    		void link(const int &p,const int &b,const int &e,const int &l,const int &r,const int &x) {
    			if(b==l&&e==r) {
    				add_edge(id[p],x,0);
    				return;
    			}
    			if(l<=mid) link(p _left,b,mid,l,std::min(mid,r),x);
    			if(r>mid) link(p _right,mid+1,e,std::max(mid+1,l),r,x);
    		}
    	#undef _left
    	#undef _right
    	#undef mid
    };
    SegmentTree t;
    inline void kahn() {
    	static std::queue<int> q;
    	for(register int i=1;i<=tot;i++) {
    		if(!ind[i]) {
    			dis[i]=d[i]?:1;
    			q.push(i);
    		}
    	}
    	while(!q.empty()) {
    		const int &x=q.front();
    		vis[x]=true;
    		for(unsigned i=0;i<e[x].size();i++) {
    			const int &y=e[x][i].to,&w=e[x][i].w;
    			if(d[y]) {
    				if(d[y]<dis[x]+w) throw 0;
    				dis[y]=d[y];
    			} else {
    				dis[y]=std::max(dis[y],dis[x]+w);
    				if(dis[y]>lim) throw 0;
    			}
    			if(!--ind[y]) q.push(y);
    		}
    		q.pop();
    	}
    	for(register int i=1;i<=tot;i++) {
    		if(!vis[i]) throw 0;
    	}
    }
    int main() {
    	const int n=tot=getint(),s=getint(),m=getint();
    	t.build(1,1,n);
    	for(register int i=0;i<s;i++) {
    		const int p=getint();
    		dis[p]=d[p]=getint();
    	}
    	for(register int i=0;i<m;i++) {
    		const int l=getint(),r=getint(),k=getint();
    		tot++;
    		int last=l;
    		for(register int i=0;i<k;i++) {
    			const int x=getint();
    			add_edge(tot,x,1);
    			if(x-1>=last) t.link(1,1,n,last,x-1,tot);
    			last=x+1;
    		}
    		if(r>=last) t.link(1,1,n,last,r,tot);
    	}
    	try {
    		kahn();
    	} catch(...) {
    		puts("NIE");
    		return 0;
    	}
    	puts("TAK");
    	for(register int i=1;i<=n;i++) {
    		printf("%d%c",dis[i]," 
    "[i==n]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    DC中为什么要用Uniquify?
    hdu 1596 find the safest road
    hdu2112 HDU Today
    hdu 2066 一个人的旅行
    poj 3026 Borg Maze
    poj 1979 Red and Black
    poj 1321 棋盘问题
    hdu 1010 Tempter of the Bone
    hdu 4861 Couple doubi
    codeforces584B Kolya and Tanya
  • 原文地址:https://www.cnblogs.com/skylee03/p/9580650.html
Copyright © 2011-2022 走看看