• UOJ#217. 【UNR #1】奇怪的线段树(广义线段树性质+上下界最小流)


    http://uoj.ac/problem/217

    题解:

    考虑查询一个区间,遍历到的叶子一定是右儿子、右儿子、……、左儿子、左儿子。

    反过来,值域连续的这样的若干节点也唯一对应一个区间。

    所以右儿子给值域相邻的右、左儿子连边,左儿子只给左儿子连边,问题相当于最小路径覆盖(每个点可以被覆盖无限次,有些至少一次)。

    拆点上下界最小流即可。

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    using namespace std;
    
    const int N = 8005;
    
    struct P {
    	int l, r, x, y, m, fa;
    	int w;
    } t[N]; int t0;
    
    int n, rt;
    
    void dg(int &i, int x, int y) {
    	i = ++ t0;
    	t[i].x = x; t[i].y = y;
    	if(x == y) {
    		scanf("%d", &t[i].w);
    		return;
    	}
    	scanf("%d %d", &t[i].w, &t[i].m);
    	dg(t[i].l, x, t[i].m);
    	dg(t[i].r, t[i].m + 1, y);
    	t[t[i].l].fa = t[t[i].r].fa = i;
    }
    
    int d[N], d0, id[N];
    
    namespace gra {
    	const int N = 1e6 + 5;
    	
    	int fi[N], to[N], nt[N], r[N], tot = 1;
    	
    	void link(int x, int y, int z) {
    		nt[++ tot] = fi[x], to[tot] = y, r[tot] = z, fi[x] = tot;
    		nt[++ tot] = fi[y], to[tot] = x, r[tot] = 0, fi[y] = tot;
    	}
    	
    	int S, T, SS, TT;
    	
    	int p[N];
    	
    	void link(int x, int y, int l, int r) {
    		p[x] -= l, p[y] += l;
    		link(x, y, r - l);
    	}
    	
    	const int inf = 1e9;
    	
    	int sump = 0;
    	
    	void rlink() {
    		fo(i, 1, TT) {
    			if(p[i] > 0) {
    				sump += p[i];
    				link(SS, i, p[i]);
    			}
    			if(p[i] < 0) {
    				link(i, TT, -p[i]);
    			}
    		}
    		link(T, S, inf);
    	}
    	
    	int w[N][2], w0;
    	
    	int cur[N];
    	
    	namespace sub {
    		int S, T;
    		int d[N], d0, dis[N];
    		
    		int bfs() {
    			fo(i, 1, max(S, T)) {
    				dis[i] = inf;
    				cur[i] = fi[i];
    			}
    			
    			dis[S] = 0, d[d0 = 1] = S;
    			for(int i = 1; i <= d0; i ++) {
    				int x = d[i];
    				for(int j = fi[x]; j; j = nt[j]) if(r[j]) {
    					int y = to[j];
    					if(dis[y] == inf) dis[y] = dis[x] + 1, d[++ d0] = y;
    				}
    			}
    			return dis[T] < inf;
    		}
    		
    		int dg(int x, int flow) {
    			if(x == T) return flow;
    			int use = 0;
    			for(int &i = cur[x]; i; i = nt[i]) if(r[i] && dis[x] + 1 == dis[to[i]]) {
    				int t = dg(to[i], min(flow - use, r[i]));
    				r[i] -= t, r[i ^ 1] += t, use += t;
    				if(use == flow) return use;
    			}
    			return use;
    		}
    		
    		int work() {
    			int ans = 0;
    			while(bfs()) {
    				ans += dg(S, inf);
    			}
    			return ans; 
    		}
    	}
    	
    	int lx[N];
    	
    	void work() {
    		w0 = n;
    		fo(i, 1, t0) if(t[i].w) {
    			w[i][0] = ++ w0;
    			w[i][1] = ++ w0;
    			lx[i] = t[t[i].fa].r == i;
    		}
    		fo(i, 1, t0) if(t[i].w) {
    			if(id[i]) {
    				link(w[i][0], w[i][1], 1, inf);
    			} else {
    				link(w[i][0], w[i][1], 0, inf);
    			}
    			int k = lx[i];
    			if(k == 1) {
    				fo(j, 1, t0) if(t[j].w && t[j].y == t[i].x - 1 && lx[j])
    					link(w[j][1], w[i][0], 0, inf);
    				if(t[i].y < n) {
    					link(w[i][1], t[i].y + 1, 0, inf);
    				}
    			} else {
    				link(t[i].x, w[i][0], 0, inf);
    				if(t[i].y < n) {
    					link(w[i][1], t[i].y + 1, 0, inf);
    				}
    			}
    		}
    		
    		S = w0 + 1, T = S + 1;
    		SS = T + 1, TT = SS + 1;
    		
    		fo(i, 1, t0) if(t[i].w) {
    			link(S, w[i][0], 0, inf);
    			link(w[i][1], T, 0, inf);
    		}
    		rlink();
    		
    		sub :: S = SS; sub :: T = TT;
    		int flow = sub :: work();
    		int ans = r[fi[S]];
    		
    		cur[SS] = cur[TT] = 0;
    		
    		sub :: S = T; sub :: T = S;
    		fi[S] = nt[fi[S]]; fi[T] = nt[fi[T]];
    		
    		ans -= sub :: work();
    		
    		pp("%d
    ", ans);
    	}
    }
    
    int main() {
    	scanf("%d", &n);
    	dg(rt, 1, n);
    	fo(i, 1, t0) if(t[i].w && t[i].fa && !t[t[i].fa].w) {
    		pp("OwO
    "); return 0;
    	}
    	fo(i, 1, t0) if(t[i].w) {
    		if(t[t[i].l].w || t[t[i].r].w) continue;
    		d[++ d0] = i;
    		id[i] = d0;
    	}
    	gra :: work();
    }
    
  • 相关阅读:
    神秘现象?多种情况比较
    [备忘]C++BUILDER的文件操作
    缘起
    [备忘]一个二维数组的冒泡排序
    无可救药地买入NDSL
    递归的实质
    [网游计划第九、十天]能力有限,做些小品
    大学有救
    struts2+convertion实现struts.xml的零配置
    BSD下的超级终端
  • 原文地址:https://www.cnblogs.com/coldchair/p/13399363.html
Copyright © 2020-2023  润新知