[BZOJ5329][SDOI2018]战略游戏(圆方树+虚树)

题意:一张无向图,每次给出一个点集,问有多少个点满足删去它后,存在点集中的两个点不连通。

算法:显然的圆方树+虚树。

建出圆方树后,答案就是所有关键点之间的路径上的圆点个数,这个直接用虚树,维护树上前缀和与右链即可。

虚树一万年不会建。。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define rep(i,l,r) for (int i=(l),_=(r); i<=_; i++)
 5 #define mem(a) memset(a,0,sizeof(a))
 6 using namespace std;
 7 
 8 const int N=400010;
 9 int n,tot,k,u,v,m,T,Q,top,clk,L[N],R[N],dfn[N],low[N],tim,stk[N];
10 int fa[N],Top[N],dep[N],dis[N],s[N],sz[N],son[N],q[N];
11 struct E{
12     int cnt,h[N],nxt[N],to[N];
13     void init(){ mem(h); cnt=0; }
14     void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
15 }G,G1;
16 
17 void Tarjan(int x,int fa){
18     dfn[x]=low[x]=++tim; stk[++top]=x;
19     for (int i=G.h[x],k; i; i=G.nxt[i])
20         if ((k=G.to[i])!=fa){
21             if (!dfn[k]){
22                 Tarjan(k,x); low[x]=min(low[x],low[k]);
23                 if (low[k]>=dfn[x]){
24                     tot++; int t; G1.add(x,tot);
25                     do { t=stk[top--]; G1.add(tot,t); } while (t!=k);
26                 }
27             }else low[x]=min(low[x],dfn[k]);
28         }
29 }
30 
31 void dfs1(int x){
32     dep[x]=dep[fa[x]]+1; dis[x]=dis[fa[x]]+(x<=n); sz[x]=1;
33     for (int i=G1.h[x]; i; i=G1.nxt[i]){
34         int k=G1.to[i]; fa[k]=x; dfs1(k); sz[x]+=sz[k];
35         if (sz[k]>sz[son[x]]) son[x]=k;
36     }
37 }
38 
39 void dfs2(int x,int tp){
40     Top[x]=tp; L[x]=++clk;
41     if (son[x]) dfs2(son[x],tp);
42     for (int i=G1.h[x],k; i; i=G1.nxt[i])
43         if ((k=G1.to[i])!=son[x]) dfs2(k,k);
44     R[x]=clk;
45 }
46 
47 int LCA(int u,int v){
48     for (; Top[u]!=Top[v]; u=fa[Top[u]])
49         if (dep[Top[u]]<dep[Top[v]]) swap(u,v);
50     return dep[u]<dep[v] ? u : v;
51 }
52 
53 bool cmp(int a,int b){ return L[a]<L[b]; }
54 
55 int main(){
56     freopen("bzoj5329.in","r",stdin);
57     freopen("bzoj5329.out","w",stdout);
58     for (scanf("%d",&T); T--; ){
59         scanf("%d%d",&n,&m); tot=n;
60         tim=clk=0; mem(dfn); mem(son); G.init(); G1.init();
61         rep(i,1,m) scanf("%d%d",&u,&v),G.add(u,v),G.add(v,u);
62         rep(i,1,n) if (!dfn[i]) Tarjan(i,0);
63         dfs1(1); dfs2(1,1);
64         for (scanf("%d",&Q); Q--; ){
65             scanf("%d",&k); int len=k;
66             rep(i,1,k) scanf("%d",&s[i]);
67             sort(s+1,s+k+1,cmp);
68             rep(i,1,k-1) s[++len]=LCA(s[i],s[i+1]);
69             sort(s+1,s+len+1,cmp); len=unique(s+1,s+len+1)-s-1;
70             int tp=0,ans=(s[1]<=n);
71             rep(i,1,len){
72                 while (tp && R[q[tp]]<L[s[i]]) tp--;
73                 if (tp) ans+=dis[s[i]]-dis[q[tp]];
74                 q[++tp]=s[i];
75             }
76             printf("%d\n",ans-k);
77         }
78     }
79     return 0;
80 }

 

posted @ 2018-06-06 19:58  HocRiser  阅读(237)  评论(0编辑  收藏  举报