zoukankan      html  css  js  c++  java
  • 【CF613D】Kingdom and its Cities

    【CF613D】Kingdom and its Cities

    题面

    洛谷

    题解

    看到关键点当然是建虚树啦。

    (f[x])表示以(x)为根的子树的答案,(g[x])表示以(x)为根的子树内是否有(x)联通的点,(c=sum_{vin son_x} g[v])

    分类讨论一下:

    • 如果一个点在原树下它和它的父亲均为关键点,那么显然不行。
    • 这个点是关键点,(f[x]+=c)(g[x]=1)
    • 这个点不是关键点,若(c>1)则断掉这个点,(++f[x],g[x]=0),否则(g[x]=1)

    这题就做(v.a.n)啦。

    代码

    #include <iostream> 
    #include <cstdio> 
    #include <cstdlib> 
    #include <cstring> 
    #include <cmath> 
    #include <algorithm> 
    using namespace std; 
    inline int gi() { 
        register int data = 0, w = 1; 
        register char ch = 0; 
        while (!isdigit(ch) && ch != '-') ch = getchar(); 
        if (ch == '-') w = -1, ch = getchar(); 
        while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); 
        return w * data; 
    } 
    const int MAX_N = 1e5 + 5; 
    struct Graph { int to, next; } e[MAX_N << 1];
    int fir1[MAX_N], fir2[MAX_N], e_cnt; 
    void clearGraph() {
    	memset(fir1, -1, sizeof(fir1)); 
    	memset(fir2, -1, sizeof(fir2)); 
    } 
    void Add_Edge(int *fir, int u, int v) { 
    	e[e_cnt] = (Graph){v, fir[u]}; 
    	fir[u] = e_cnt++; 
    }
    namespace Tree { 
        int fa[MAX_N], dep[MAX_N], size[MAX_N], top[MAX_N], son[MAX_N], dfn[MAX_N], tim; 
        void dfs1(int x) { 
            dfn[x] = ++tim; 
            size[x] = 1, dep[x] = dep[fa[x]] + 1; 
            for (int i = fir1[x]; ~i; i = e[i].next) {
                int v = e[i].to; if (v == fa[x]) continue; 
                fa[v] = x; dfs1(v); size[x] += size[v]; 
                if (size[v] > size[son[x]]) son[x] = v; 
            } 
        } 
        void dfs2(int x, int tp) {
            top[x] = tp; 
            if (son[x]) dfs2(son[x], tp); 
            for (int i = fir1[x]; ~i; i = e[i].next) {
                int v = e[i].to; if (v == fa[x] || v == son[x]) continue; 
                dfs2(v, v); 
            } 
        } 
        int LCA(int x, int y) { 
            while (top[x] != top[y]) { 
                if (dep[top[x]] < dep[top[y]]) swap(x, y); 
                x = fa[top[x]]; 
            } 
            return dep[x] < dep[y] ? x : y; 
        } 
    }
    using Tree::dfn; using Tree::LCA; 
    int N, M, K, a[MAX_N], f[MAX_N];
    bool g[MAX_N], key[MAX_N]; 
    bool cmp(const int &i, const int &j) { return dfn[i] < dfn[j]; } 
    void build() {
    	static int stk[MAX_N], top;
    	e_cnt = 0; top = 0; 
    	sort(&a[1], &a[K + 1], cmp); 
    	for (int i = 1; i <= K; i++) if (a[i] != a[i - 1]) stk[++top] = a[i];
    	K = top; 
    	for (int i = 1; i <= K; i++) a[i] = stk[i]; 
    	stk[top = 1] = 1, fir2[1] = -1; 
    	for (int i = 1; i <= K; i++) { 
    		if (a[i] == 1) continue;
    	    int lca = LCA(a[i], stk[top]);
    		if (lca != stk[top]) { 
    			while (dfn[lca] < dfn[stk[top - 1]]) { 
    				int u = stk[top], v = stk[top - 1]; 
    				Add_Edge(fir2, u, v), Add_Edge(fir2, v, u); 
    				--top; 
    			} 
    			if (dfn[lca] > dfn[stk[top - 1]]) { 
    				fir2[lca] = -1; int u = lca, v = stk[top];
    				Add_Edge(fir2, u, v), Add_Edge(fir2, v, u);
    				stk[top] = lca; 
    			} else { 
    				int u = lca, v = stk[top--]; 
    				Add_Edge(fir2, u, v), Add_Edge(fir2, v, u); 
    			} 
    		} 
    		fir2[a[i]] = -1, stk[++top] = a[i]; 
    	} 
    	for (int i = 1; i < top; i++) {
    		int u = stk[i], v = stk[i + 1]; 
    		Add_Edge(fir2, u, v), Add_Edge(fir2, v, u); 
    	} 
    } 
    void Dp(int x, int fa) { 
    	f[x] = g[x] = 0; 
    	int c = 0; 
    	for (int i = fir2[x]; ~i; i = e[i].next) { 
    		int v = e[i].to; if (v == fa) continue; 
    		Dp(v, x); 
    		f[x] += f[v], c += g[v]; 
    	} 
    	if (key[x]) g[x] = 1, f[x] += c; 
    	else if (c > 1) g[x] = 0, ++f[x]; 
    	else g[x] = c; 
    } 
    int main () { 
    #ifndef ONLINE_JUDGE 
        freopen("cpp.in", "r", stdin); 
    #endif
    	clearGraph(); 
    	N = gi();
    	for (int i = 1; i < N; i++) { 
    		int u = gi(), v = gi(); 
    		Add_Edge(fir1, u, v), Add_Edge(fir1, v, u); 
    	}
    	Tree::dfs1(1), Tree::dfs2(1, 1); 
    	M = gi(); 
    	while (M--) {
    		K = gi(); for (int i = 1; i <= K; i++) key[a[i] = gi()] = 1;
    		bool flg = 1; 
    		for (int i = 1; i <= K && flg; i++) if (key[Tree::fa[a[i]]]) flg = 0; 
    		if (!flg) { puts("-1"); goto NXT; } 
    		build(); 
    		Dp(1, 0); 
    		printf("%d
    ", f[1]); 
    	  NXT : 
    		for (int i = 1; i <= K; i++) key[a[i]] = 0; 
    	} 
    	return 0; 
    } 
    
  • 相关阅读:
    BZOJ 1040 (ZJOI 2008) 骑士
    BZOJ 1037 (ZJOI 2008) 生日聚会
    ZJOI 2006 物流运输 bzoj1003
    ZJOI 2006 物流运输 bzoj1003
    NOI2001 炮兵阵地 洛谷2704
    NOI2001 炮兵阵地 洛谷2704
    JLOI 2013 卡牌游戏 bzoj3191
    JLOI 2013 卡牌游戏 bzoj3191
    Noip 2012 day2t1 同余方程
    bzoj 1191 [HNOI2006]超级英雄Hero——二分图匹配
  • 原文地址:https://www.cnblogs.com/heyujun/p/10360273.html
Copyright © 2011-2022 走看看