CF613D Kingdom and its Cities
【题意】
首先特判掉无解的情况,也就是选了x和fa[x]的情况
然后我们可以建立虚树,给指定的k个点设置点权为1(为了区分lca)
设f[x]为以x为子树的答案,g[x]为这个点及其子树内是否有需要被割的点
考虑这个点是不是关键点,如果是原来给定的点,f[x]+=g[xson],也就是让他的所有需要被断开的儿子都断开
如果这个点不是关键点,那么我们考虑如果他有多个儿子都需要被断开,那就把这个点断开f[x]+=1,如果只有一个就让g[x]=1,向上传递等待被断
一定记得在dfsdp的时候清零head否则会锅:(
【代码】
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+5; int n,q,m,tot,head[maxn],nh[maxn],etot; struct edge { int to,nxt; }e[maxn<<1],ne[maxn<<1]; void add(int x,int y) { e[++tot].to=y; e[tot].nxt=head[x]; head[x]=tot; } void addedge(int x,int y) { ne[++etot].to=y; ne[etot].nxt=nh[x]; nh[x]=etot; } int f[maxn][20],dep[maxn],vis[maxn],qu[maxn]; int dfn[maxn],dfstime,st[maxn],top; void dfs(int u,int fa) { f[u][0]=fa; dep[u]=dep[fa]+1; dfn[u]=++dfstime; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(to==fa) continue; dfs(to,u); } } void lca_init() { for(int j=1;j<=18;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; } bool cmp(int a,int b) { return dfn[a]<dfn[b]; } int getlca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int i=18;i>=0;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i]; if(x==y) return x; for(int i=18;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } int g[maxn]; int dfsdp(int u) { int ucnt=0,uneed=0; for(int i=nh[u];i;i=ne[i].nxt) { int to=ne[i].to; ucnt+=dfsdp(to); uneed+=g[to]; } if(vis[u]) ucnt+=uneed,g[u]=1; else if(uneed>1) ucnt++,g[u]=false; else g[u]=uneed?1:0; vis[u]=0; nh[u]=0; return ucnt; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d",&n); int x,y; for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1,0); lca_init(); scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%d",&q); bool flag=0; etot=0; for(int j=1;j<=q;j++) { scanf("%d",&qu[j]); vis[qu[j]]=1; } for(int j=1;j<=q;j++) if(vis[f[qu[j]][0]]) flag=1; if(flag) { for(int j=1;j<=q;j++) vis[qu[j]]=0; printf("-1\n"); continue; } sort(qu+1,qu+q+1,cmp); st[top=1]=qu[1]; for(int i=2;i<=q;i++) { int z=getlca(qu[i],st[top]); while(dep[st[top-1]]>dep[z]) { addedge(st[top-1],st[top]); top--; } if(st[top]!=z) { addedge(z,st[top]); if(st[top-1]==z) top--; else st[top]=z; } st[++top]=qu[i]; } while(--top) addedge(st[top],st[top+1]); printf("%d\n",dfsdp(st[1])); } return 0; }