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

    Meanwhile, the kingdom of K is getting ready for the marriage of the King's daughter. However, in order not to lose face in front of the relatives, the King should first finish reforms in his kingdom. As the King can not wait for his daughter's marriage, reforms must be finished as soon as possible.

    The kingdom currently consists of n n n cities. Cities are connected by n−1bidirectional road, such that one can get from any city to any other city. As the King had to save a lot, there is only one path between any two cities.

    What is the point of the reform? The key ministries of the state should be relocated to distinct cities (we call such cities important). However, due to the fact that there is a high risk of an attack by barbarians it must be done carefully. The King has made several plans, each of which is described by a set of important cities, and now wonders what is the best plan.

    Barbarians can capture some of the cities that are not important (the important ones will have enough protection for sure), after that the captured city becomes impassable. In particular, an interesting feature of the plan is the minimum number of cities that the barbarians need to capture in order to make all the important cities isolated, that is, from all important cities it would be impossible to reach any other important city.

    Help the King to calculate this characteristic for each of his plan.

    输入格式

    The first line of the input contains integer n n n ( 1<=n<=100000 ) — the number of cities in the kingdom.

    Each of the next n−1 n-1 n−1 lines contains two distinct integers ui vi ( 1<=ui,vi<=n ) — the indices of the cities connected by the i i i -th road. It is guaranteed that you can get from any city to any other one moving only along the existing roads.

    The next line contains a single integer q ( 1<=q<=100000 ) — the number of King's plans.

    Each of the next q q q lines looks as follows: first goes number ki— the number of important cities in the King's plan, ( 1<=ki<=n ), then follow exactly ki space-separated pairwise distinct numbers from 1 to n n n — the numbers of important cities in this plan.

    The sum of all ki does't exceed 100000

    输出格式

    For each plan print a single integer — the minimum number of cities that the barbarians need to capture, or print −1if all the barbarians' attempts to isolate important cities will not be effective.

    题意翻译

    一个王国有n座城市,城市之间由n-1条道路相连,形成一个树结构,国王决定将一些城市设为重要城市。

    这个国家有的时候会遭受外敌入侵,重要城市由于加强了防护,一定不会被占领。而非重要城市一旦被占领,这座城市就不能通行。

    国王定了若干选择重要城市的计划,他想知道,对于每个计划,外敌至少要占领多少个非重要城市,才会导致重要城市之间两两不连通。如果外敌无论如何都不可能导致这种局面,输出-1

    感谢@litble 提供的翻译

    输入输出样例

    输入 #1

    4
    1 3
    2 3
    4 3
    4
    2 1 2
    3 2 3 4
    3 1 2 4
    4 1 2 3 4
    

    输出 #1

    1
    -1
    1
    -1
    

    输入 #2

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

    输出 #2

    2
    

    说明/提示

    In the first sample, in the first and the third King's plan barbarians can capture the city 3, and that will be enough. In the second and the fourth plans all their attempts will not be effective.

    In the second sample the cities to capture are 3 and 5.

    这种有 (sum k_i <= 1e5) 的肯定与虚树有关 , 这好像就是一个虚树模板题。

    建出虚树之后 , dp(或者叫贪心),大力讨论即可。

    代码里有一些之前犯的傻屌错误,见注释。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<cstdlib>
    using namespace std;
    const int N = 101000;
    inline int read()
    {
    	register int x = 0 , f = 0; register char c = getchar();
    	while(c < '0' || c > '9') f |= c == '-' , c = getchar();
    	while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
    	return f ? -x : x;
    }
    #define RQ { puts("RQ"); /*exit(0);*/ }
    int n , cnt , id , top , ans;
    int head[N] , dfn[N] , a[N] , f[N][18] , sta[N] , d[N] , siz[N];
    vector<int> ed[N];
    struct edge{int v , nex; } e[N<<1];
    inline void add(int u , int v) { e[++cnt].v = v; e[cnt].nex = head[u]; head[u] = cnt; return ;}
    inline bool cmp(const int &A , const int &B) { return dfn[A] < dfn[B]; }
    inline void addc(int u , int v) { /*ed[u].push_back(v);*/ ed[v].push_back(u); return ; }
    
    void dfs(int x , int fa)
    {
    	dfn[x] = ++id; d[x] = d[fa] + 1;
    	for(int i = 1 ; i <= 17 ; ++i) f[x][i] = f[f[x][i-1]][i-1];
    	for(int i = head[x] , v ; i ; i = e[i].nex)
    	{
    		v = e[i].v; if(v == fa) continue; 
    		f[v][0] = x; dfs(v , x);
    	}
    	return ;
    }
    
    int LCA(int x , int y)
    {
    	if(x == y) return x;
    	int i; if(d[x] < d[y]) swap(x , y);
    	for(i = 17 ; i >= 0 ; --i) if(d[f[x][i]] >= d[y]) x = f[x][i];
    	if(x == y) return x;
    	for(i = 17 ; i >= 0 ; --i) if(f[x][i] ^ f[y][i]) x = f[x][i] , y = f[y][i];
    	return f[x][0];
    }
    
    void build_tree(int k)
    {
    	top = 0; int i = 1;// 我是傻子 , 居然让 k++ 
    	if(a[1] != 1) sta[top = 1] = 1; // else sta[top = 1] = a[1] , i = 2;
    	for(i = 1 ; i <= k ; ++i)
    	{
    		int p = LCA(sta[top] , a[i]);
    		if(p == sta[top]) { sta[++top] = a[i]; continue; }
    		while(top > 1 && d[sta[top-1]] >= d[p]) addc(sta[top] , sta[top-1]) , top--;
    		if(sta[top] != p) addc(sta[top] , p) , sta[top] = p; // addc(sta[top] , sta[p]) ..............
    		sta[++top] = a[i];
    	}
    	while(top > 1) addc(sta[top] , sta[top-1]) , top--;
    	return ;
    }
    
    void dfs2(int x)
    {
    	int i = 0 , s = ed[x].size() , v;
    	if(siz[x])
    	{
    		for(i = 0 ; i < s ; ++i)
    		{
    			v = ed[x][i];
    			dfs2(v); if(siz[v]) { ans++; siz[v] = 0; }
    		}
    	}
    	else
    	{
    		for(i = 0 ; i < s ; ++i)
    		{
    			v = ed[x][i];
    			dfs2(v); siz[x] += siz[v]; siz[v] = 0;
    		}
    		if(siz[x] > 1) siz[x] = 0 , ans++;
    	}
    	ed[x].clear();
    	return ; 
    }
    
    int main() 
    {
    	n = read();
    	for(int i = 1 , a , b ; i < n ; ++i) 
    	{
    		a = read() , b = read();
    		add(a , b); add(b , a);
    	}
    	dfs(1 , 0);
    	int m = read() , k , i , j;
    	for(i = 1 ; i <= m ; ++i)
    	{
    		k = read();
    		for(j = 1 ; j <= k ; ++j) a[j] = read() , siz[a[j]] = 1;
    		sort(a + 1 , a + 1 + k , cmp);
    //		for(j = 2 ; j <= k ; ++j) if(f[a[j]][0] == a[j-1]) { puts("-1"); break; } 这样判非法不对 , 有反例 
    //		if(j <= k) continue;
    //		for(j = 1 ; j <= k ; ++j) siz[a[j]] = 1;
    		for(j = 1 ; j <= k ; ++j) if(siz[f[a[j]][0]]) break;
    		if(j <= k) { puts("-1"); for(j = 1 ; j <= k ; ++j) siz[a[j]] = 0; continue; }
    		build_tree(k); ans = 0;
    		dfs2(1); printf("%d
    " , ans); siz[1] = 0; ed[1].clear(); // 把 1 清空 
    //		for(j = 1 ; j <= k ; ++j) Key[a[j]] = 0;  不能只清空关键节点的数据, 还有他们的lca 
    //		for(j = 1 ; j <= k ; ++j) ed[a[j]].clear();
    	}
    	return 0;
    }
    /*
    4
    1 3
    2 3
    4 3
    4
    2 1 2
    3 2 3 4
    3 1 2 4
    4 1 2 3 4
    */
    
  • 相关阅读:
    线程(java课堂笔记)
    java中的各种流(老师的有道云笔记)
    面向对象(java菜鸟的课堂笔记)
    泛型(java菜鸟的课堂笔记)
    我做的第一个程序(菜鸟的java课堂笔记)
    java中的一些规则(菜鸟的课堂笔记)
    一位菜鸟的java 最基础笔记
    spatial index (空间索引)
    hadoop 的疑问
    numpy 矩阵的运算
  • 原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12159425.html
Copyright © 2011-2022 走看看