• bzoj4383 [POI2015]Pustynia 拓扑排序+差分约束+线段树优化建图


    题目传送门

    https://lydsy.com/JudgeOnline/problem.php?id=4383

    题解

    暴力的做法显然是把所有的条件拆分以后暴力建一条有向边表示小于关系。

    因为不存在零环,所以随后可以用拓扑排序来解决。


    考虑如何优化。

    第一个优化比较显而易见,对于一个条件,新建一个虚点,连向所有给出的点。

    第二个是,我们可以发现,给定这 (k) 个点以后,实际上需要建的边是从最多 (k + 1) 个区间中引出的,所以可以考虑线段树优化建图。

    然后就可以和上面一样的,因为不存在零环,所以随后可以用拓扑排序来解决。

    然后这样的时间复杂度是 (O((m+sum k)log n))


    这似乎是我第一次写线段树优化建图呢~虽然一年前就已经学过了,但是一直没写过。

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 100000 * 6 + 7;
    const int M = 100000 * (4 + 3 + 17 + 17) + 7;
    
    #define lc o << 1
    #define rc o << 1 | 1
    
    int n, ns, m, nod;
    int dp[N], nd[N], idg[N], pre[N], rel[N], tmp[N], q[N];
    
    struct Edge { int to, ne, w; } g[M]; int head[N], tot;
    inline void addedge(int x, int y, int z) { g[++tot].to = y, g[tot].w = z, g[tot].ne = head[x], head[x] = tot; }
    inline void adde(int x, int y, int z) { addedge(x, y, z), addedge(y, x, z); }
    
    inline void add_e(int x, int y, int z) { ++idg[y], addedge(x, y, z); }
    
    inline void build(int o, int L, int R) {
    	if (L == R) return (void)(rel[L] = o, pre[o] = L);
    	int M = (L + R) >> 1;
    	add_e(lc, o, 0), build(lc, L, M);
    	add_e(rc, o, 0), build(rc, M + 1, R);
    }
    inline void addi(int o, int L, int R, int l, int r, int x) {
    //	dbg("o = %d, L = %d, R = %d, l = %d, r = %d, x = %d
    ", o, L, R, l, r, x);
    	if (l <= L && R <= r) return add_e(o, x, 1);
    	int M = (L + R) >> 1;
    	if (l <= M) addi(lc, L, M, l, r, x);
    	if (r > M) addi(rc, M + 1, R, l, r, x);
    }
    
    inline void work() {
    	int hd = 0, tl = 0;
    	for (int i = 1; i <= nod; ++i) if (idg[i] == 0) q[++tl] = i, smax(dp[i], 1);
    	while (hd < tl) {
    		int x = q[++hd];
    //		if (dp[x] >= n) dbg("******* x = %d, dp[x] = %d, nd[x] = %d
    ", x, dp[x], nd[x]);
    		if (nd[x]) {
    			if (dp[x] > nd[x]) {
    				puts("NIE");
    				return;
    			} else dp[x] = nd[x];
    		}
    		for fec(i, x, y) {
    			smax(dp[y], dp[x] + g[i].w);
    			if (!--idg[y]) q[++tl] = y;
    		}
    	}
    	for (int i = 1; i <= n; ++i) if (!dp[rel[i]] || dp[rel[i]] > 1e9) {
    		puts("NIE");
    		return;
    	}
    	puts("TAK");
    	for (int i = 1; i <= n; ++i) printf("%d%c", dp[rel[i]], " 
    "[i == n]);
    }
    
    inline void init() {
    	read(n), read(ns), read(m);
    	int x, y;
    	build(1, 1, n);
    	nod = n << 2;
    	for (int i = 1; i <= ns; ++i) read(x), read(y), dp[rel[x]] = nd[rel[x]] = y;
    	for (int i = 1; i <= m; ++i) {
    		int l, r, k;
    		read(l), read(r), read(k);
    		++nod;
    		for (int i = 1; i <= k; ++i) {
    			read(tmp[i]);
    			add_e(nod, rel[tmp[i]], 0);
    			if (i == 1) tmp[i] > l ? addi(1, 1, n, l, tmp[i] - 1, nod) : (void)0;
    			else tmp[i] - tmp[i - 1] > 1 ? addi(1, 1, n, tmp[i - 1] + 1, tmp[i] - 1, nod) : (void)0;
    		}
    		if (tmp[k] != r) addi(1, 1, n, tmp[k] + 1, r, nod);
    	}
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    isEmpty和isBlank区别
    java加密算法相关
    页面跳转、替换、刷新
    打开一个网站都经过了什么
    css3动画和JS+DOM动画和JS+canvas动画比较
    canvas如何兼容IE8
    移动端的300毫秒延迟问题
    几道前端的面试题
    js执行过程
    微信查看网页源代码的方法
  • 原文地址:https://www.cnblogs.com/hankeke/p/bzoj4383.html
Copyright © 2020-2023  润新知