解题:SDOI2018 战略游戏

题面

先圆方树然后建虚树,答案就是虚树大小。虚树没必要建出来,把原来的点的点权设为1,直接dfs序排序后相邻点求距离加上首尾两个点的距离,最后除以二(画一下可以发现是正反算了两遍),注意还要去掉询问点和补上首尾两个点的LCA

  1 #include<cstdio>
  2 #include<vector>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define vint vector<int>
  6 #define vit vector<int> ::iterator
  7 using namespace std;
  8 const int N=200005,M=800005;
  9 int T,n,m,c,q,o,t1,t2,rt,pt,cnt,Cnt,tot;
 10 int dfn[N],low[N],stk[N],isc[N],col[N];
 11 int p[N],noww[M],goal[M],P[N],Noww[M],Goal[M];
 12 int siz[N],dep[N],fth[N],imp[N],top[N],qry[M],dis[N]; vint pbc[N];
 13 void Link(int f,int t)
 14 {
 15     noww[++cnt]=p[f];
 16     goal[cnt]=t,p[f]=cnt;
 17     noww[++cnt]=p[t];
 18     goal[cnt]=f,p[t]=cnt;
 19 }
 20 void Linka(int f,int t)
 21 {
 22     Noww[++Cnt]=P[f];
 23     Goal[Cnt]=t,P[f]=Cnt;
 24     Noww[++Cnt]=P[t];
 25     Goal[Cnt]=f,P[t]=Cnt;
 26 }
 27 bool cmp(int a,int b)
 28 {
 29     return dfn[a]<dfn[b];
 30 }
 31 void Init()
 32 {
 33     memset(p,0,sizeof p);
 34     memset(P,0,sizeof P);
 35     memset(dfn,0,sizeof dfn);
 36     memset(low,0,sizeof low);
 37     memset(imp,0,sizeof imp);
 38     memset(top,0,sizeof top);
 39     for(int i=1;i<=c;i++) pbc[i].clear();
 40     cnt=Cnt=tot=c=0;
 41 }
 42 void RTPBC(int nde)
 43 {
 44     int tmp=0;
 45     dfn[nde]=low[nde]=++tot,stk[++pt]=nde;
 46     for(int i=p[nde],g;i;i=noww[i])
 47         if(!dfn[g=goal[i]])    
 48         {
 49             RTPBC(g),low[nde]=min(low[nde],low[g]);
 50             if(dfn[nde]<=low[g])
 51             {
 52                 if(nde!=rt||++tmp>1) isc[nde]=true;
 53                 int tep; c++;
 54                 do
 55                 {
 56                     tep=stk[pt--],col[tep]=c;
 57                     pbc[c].push_back(tep);
 58                 }while(tep!=g);
 59                 pbc[c].push_back(nde);
 60             }
 61         }
 62         else low[nde]=min(low[nde],dfn[g]);
 63 }
 64 void DFS(int nde,int far,int dth)
 65 {
 66     int tmp=0;
 67     siz[nde]=1,fth[nde]=far,dep[nde]=dth;
 68     for(int i=P[nde],g;i;i=Noww[i])
 69         if((g=Goal[i])!=far)
 70         {
 71             dis[g]=dis[nde]+(g<=n);
 72             DFS(g,nde,dth+1),siz[nde]+=siz[g];
 73             if(siz[g]>tmp) tmp=siz[g],imp[nde]=g;
 74         }
 75 }
 76 void Mark(int nde,int upt)
 77 {
 78     top[nde]=upt,dfn[nde]=++tot;
 79     if(imp[nde])
 80     {
 81         Mark(imp[nde],upt);
 82         for(int i=P[nde],g;i;i=Noww[i])
 83             if((g=Goal[i])!=fth[nde]&&g!=imp[nde]) Mark(g,g);
 84     }
 85 }
 86 int LCA(int x,int y)
 87 {
 88     while(top[x]!=top[y])
 89     {
 90         if(dep[top[x]]<dep[top[y]]) 
 91             swap(x,y); x=fth[top[x]];
 92     }
 93     return dep[x]<dep[y]?x:y;
 94 }
 95 int Dist(int x,int y)
 96 {
 97     int lca=LCA(x,y);
 98     return dis[x]+dis[y]-2*dis[lca];
 99 }
100 int main()
101 {
102     scanf("%d",&T);
103     while(T--)
104     {
105         Init();
106         scanf("%d%d",&n,&m);
107         for(int i=1;i<=m;i++)
108             scanf("%d%d",&t1,&t2),Link(t1,t2);
109         RTPBC(rt=1);
110         for(int i=1;i<=c;i++)
111             for(vit it=pbc[i].begin();it!=pbc[i].end();it++) Linka(*it,n+i);
112         tot=0,DFS(1,0,1),Mark(1,1);
113         scanf("%d",&q);
114         while(q--)
115         {
116             scanf("%d",&o); int ans=0;
117             for(int i=1;i<=o;i++) scanf("%d",&qry[i]);
118             sort(qry+1,qry+1+o,cmp),qry[++o]=qry[1];
119             for(int i=2;i<=o;i++) ans+=Dist(qry[i],qry[i-1]);
120             printf("%d\n",(ans>>1)-o+1+(LCA(qry[o],qry[o-1])<=n));
121         }
122     }
123     return 0;
124 }
View Code

猜你喜欢

转载自www.cnblogs.com/ydnhaha/p/10617126.html