题目链接:http://codeforces.com/contest/613/problem/D
题意概述:
给出一棵树,每次询问一些点,计算最少删除几个点可以让询问的点两两不连通,无解输出-1。保证询问的点总数不大于300000。
分析:
先考虑遍历的做法,统计每个点代表的子树中联通询问点的数量。
这个点不是询问点:如果有至少两个不同的子树中有询问点那么当前点一定被删除,因为这个时候不删除之后这两个点就是联通的;同时除了在更深的地方遇见第一种情况之外没有必要删除那些点;没有点不用管,只有一个点返回1。
这个点是询问点:每有一颗子树中有儿子就删除掉一个点。
判断无解:树上两个相邻的点都是询问点。
然后建立虚树在上面跑这个算法就可以了,减少无谓遍历的点的数量。
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include<set> 9 #include 10 #include 11 #include 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){ 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<) 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<) 95 if((1<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 }
转载于:https://www.cnblogs.com/KKKorange/p/8763262.html