Codeforces Round #613 Div.1 D.Kingdom and its Cities 贪心+虚树

题目链接:http://codeforces.com/contest/613/problem/D

 

题意概述:

  给出一棵树,每次询问一些点,计算最少删除几个点可以让询问的点两两不连通,无解输出-1。保证询问的点总数不大于300000。

 

分析:

        先考虑遍历的做法,统计每个点代表的子树中联通询问点的数量。

        这个点不是询问点:如果有至少两个不同的子树中有询问点那么当前点一定被删除,因为这个时候不删除之后这两个点就是联通的;同时除了在更深的地方遇见第一种情况之外没有必要删除那些点;没有点不用管,只有一个点返回1。

  这个点是询问点:每有一颗子树中有儿子就删除掉一个点。

  判断无解:树上两个相邻的点都是询问点。

  然后建立虚树在上面跑这个算法就可以了,减少无谓遍历的点的数量。

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<queue>
  8 #include<set>
  9 #include<map>
 10 #include<vector>
 11 #include<cctype>
 12 using namespace std;
 13 const int maxn=300005;
 14 
 15 int N,Q;
 16 struct edge{ int to,next; }E[maxn<<1];
 17 int first[maxn],np,fa[maxn][21],dep[maxn],s[maxn],s_top;
 18 int dfn[maxn],dfs_clock,stk[maxn],top,use[maxn],u_top;
 19 bool inq[maxn];
 20 struct vTree{
 21     static const int maxnode=300005;
 22     int first[maxnode],np,ans; bool vis[maxnode];
 23     edge E[maxnode<<1];
 24     vTree(){
 25         memset(first,0,sizeof(first));
 26         np=ans=0;
 27         memset(vis,0,sizeof(vis));
 28     }
 29     void add_edge(int u,int v){
 30         E[++np]=(edge){v,first[u]};
 31         first[u]=np;
 32     }
 33     int DFS(int i,int f){
 34         int cnt=0;
 35         for(int p=first[i];p;p=E[p].next){
 36             int j=E[p].to;
 37             if(j==f) continue;
 38             if(DFS(j,i)){
 39                 if(vis[i]) ans++;
 40                 else cnt++;
 41             }
 42         }
 43         if(vis[i]) return 1;
 44         if(cnt>1){ ans++; return 0; }
 45         return cnt;
 46     }
 47 }vt;
 48 
 49 void _scanf(int &x)
 50 {
 51     x=0;
 52     char ch=getchar();
 53     while(ch<'0'||ch>'9') ch=getchar();
 54     while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
 55 }
 56 int out_cnt; char out[15];
 57 void _printf(int x)
 58 {
 59     if(x<0) putchar('-'),x=-x;
 60     out[++out_cnt]=x%10+'0',x/=10;
 61     while(x) out[++out_cnt]=x%10+'0',x/=10;
 62     while(out_cnt) putchar(out[out_cnt--]);
 63     putchar('\n');
 64 }
 65 void add_edge(int u,int v)
 66 {
 67     E[++np]=(edge){v,first[u]};
 68     first[u]=np;
 69 }
 70 void data_in()
 71 {
 72     _scanf(N);
 73     int x,y;
 74     for(int i=1;i<N;i++){
 75         _scanf(x);_scanf(y);
 76         add_edge(x,y); add_edge(y,x);
 77     }
 78     _scanf(Q);
 79 }
 80 void ready(int i,int f,int d)
 81 {
 82     fa[i][0]=f,dep[i]=d,dfn[i]=++dfs_clock;
 83     for(int j=1;(1<<j)<d;j++)
 84         fa[i][j]=fa[fa[i][j-1]][j-1];
 85     for(int p=first[i];p;p=E[p].next){
 86         if(E[p].to==f) continue;
 87         ready(E[p].to,i,d+1);
 88     }
 89 }
 90 int LCA(int x,int y)
 91 {
 92     if(dep[x]<dep[y]) swap(x,y);
 93     int len=dep[x]-dep[y];
 94     for(int i=0;(1<<i)<=len;i++)
 95         if((1<<i)&len) x=fa[x][i];
 96     if(x==y) return x;
 97     for(int i=18;i>=0;i--)
 98         if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
 99     return fa[x][0];
100 }
101 bool cmp(int x,int y) { return dfn[x]<dfn[y]; }
102 void build_vt()
103 {
104     stk[++top]=1,inq[1]=1,use[++u_top]=1;
105     if(s[1]!=1) stk[++top]=s[1],inq[s[1]]=1,use[++u_top]=s[1];
106     for(int j=2;j<=s_top;j++){
107         int z=LCA(s[j],s[j-1]);
108         while(top>1&&dep[stk[top-1]]>dep[z]){
109             vt.add_edge(stk[top-1],stk[top]);
110             vt.add_edge(stk[top],stk[top-1]);
111             top--;
112         }
113         if(top&&dep[stk[top]]>dep[z]){
114             vt.add_edge(stk[top],z);
115             vt.add_edge(z,stk[top]);
116             top--;
117         }
118         if(!inq[z]) inq[z]=1,stk[++top]=z,use[++u_top]=z;
119         if(!inq[s[j]]) inq[s[j]]=1,stk[++top]=s[j],use[++u_top]=s[j];
120     }
121     while(top>1){
122         vt.add_edge(stk[top-1],stk[top]);
123         vt.add_edge(stk[top],stk[top-1]);
124         top--;
125     }
126     top=0;
127 }
128 void work()
129 {
130     ready(1,0,1);
131     int k,x;
132     for(int i=1;i<=Q;i++){
133         _scanf(k);
134         for(int j=1;j<=k;j++){
135             _scanf(x);
136             s[++s_top]=x,vt.vis[x]=1;
137         }
138         bool ok=1;
139         for(int j=1;j<=s_top;j++)
140             if(vt.vis[fa[s[j]][0]]){ ok=0; break; }
141         if(!ok) _printf(-1);
142         else{
143             sort(s+1,s+s_top+1,cmp);
144             build_vt();
145             vt.DFS(1,0);
146             _printf(vt.ans);
147         }
148         while(s_top) vt.vis[s[s_top--]]=0;
149         while(u_top) inq[use[u_top]]=0,vt.first[use[u_top]]=0,u_top--;
150         vt.np=vt.ans=0;
151     }
152 }
153 int main()
154 {
155     data_in();
156     work();
157     return 0;
158 }
View Code

 

posted @ 2018-04-09 21:58  KKKorange  阅读(253)  评论(0编辑  收藏  举报