2 条题解
-
0
题目要求摧毁一个点使得两个关键点不连通,显然摧毁的点只能是割点。所以我们先求出割点并且建立出原图的圆方树。
那么圆方树是什么呢?我们把原图的每个点看作圆点,给每个点双(BCC)新建一个方点,然后让每个圆点向对应的点双方点建边。显然,新图的边只会连接圆点和方点,所以是一棵树。并且只有割点会同时连向若干个方点,因为只有割点同时属于多个点双。
现在我们考虑哪些点可以摧毁。对于一个点 ,如果它可以摧毁,只可能是它的子树和外子树都有关键点(一类),或者它的多个子节点的子树内都有关键点(二类),并且它需要是割点。
这样我们可以先预处理出一个 数组, 表示从树根到 节点之间割点的个数,是一个前缀和。
然后每组询问建出虚树, 表示 子树内关键点个数。首先考虑一类,如果 并且 ,也就是内外子树都存在关键点,那么 到 之间的割点都可以被摧毁,产生的贡献就是 ,当然,如果 也是关键点,贡献要减去一。接下来考虑二类,我们可以记录一个 ,表示有多少棵子节点的子树内有关键点。如果 就说明可以摧毁 点,但依然要判断 不是关键点并且 是割点。
下面是 AC 代码。
#include <bits/stdc++.h> using namespace std; #define int long long const int INF = 0x7f7f7f7f; int Q,n,m,q,ans=0,a[200005],ls[200005]; int ee,h[200005],nex[200005<<1],to[200005<<1]; int low[200005],bcc,cut[200005]; int dep[200005],fa[200005][20],dfn[200005],sum[200005]; int top,sk[200005],siz[200005]; vector<int> c[200005]; void addedge(int x,int y) { nex[++ee] = h[x], to[ee] = y, h[x] = ee; } void tarjin(int x,int fa) { int ch=0; dfn[x] = low[x] = ++dfn[0]; for(int i=h[x];i;i=nex[i]) { if(dfn[to[i]]==0) { sk[++top] = to[i]; tarjin(to[i],x); low[x] = min(low[x],low[to[i]]); if(x==fa) ch++; else if(low[to[i]]>=dfn[x]) cut[x] = 1; if(low[to[i]]>=dfn[x]) { bcc++; while(sk[top]!=to[i]) c[bcc].push_back(sk[top]), top--; c[bcc].push_back(sk[top]), top--; c[bcc].push_back(x); } } else if(to[i]!=fa) low[x] = min(low[x],dfn[to[i]]); } if(x==fa && ch>=2) cut[x] = 1; } void dfs0(int x,int pre) { dep[x] = dep[pre]+1, fa[x][0] = pre, dfn[x] = ++dfn[0], sum[x] = sum[pre]+cut[x]; for(int j=1;j<20;j++) fa[x][j] = fa[fa[x][j-1]][j-1]; for(int i=h[x];i;i=nex[i]) if(to[i]!=pre) dfs0(to[i],x); } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); while(dep[x]>dep[y]) x = fa[x][(int)log2(dep[x]-dep[y])]; if(x==y) return y; for(int k=19;k>=0;k--) if(fa[x][k]!=fa[y][k]) x = fa[x][k], y = fa[y][k]; return fa[x][0]; } bool cmp(int x,int y) { return dfn[x]<dfn[y]; } void build() { ee = top = 0; sort(ls+1,ls+1+m,cmp); if(ls[1]!=1) sk[++top] = 1; for(int i=1;i<=m;i++) { if(top==0) { sk[++top] = ls[i]; continue; } int z=lca(sk[top],ls[i]); while(top>1 && dep[z]<dep[sk[top-1]]) addedge(sk[top],sk[top-1]), addedge(sk[top-1],sk[top]), top--; if(dep[z]<dep[sk[top]]) addedge(sk[top],z), addedge(z,sk[top]), top--; if(top==0 || sk[top]!=z) sk[++top] = z; sk[++top] = ls[i]; } while(--top) addedge(sk[top],sk[top+1]), addedge(sk[top+1],sk[top]); } void dfs1(int x,int pre) { siz[x] = a[x]; for(int i=h[x];i;i=nex[i]) if(to[i]!=pre) dfs1(to[i],x), siz[x] += siz[to[i]]; } void dfs(int x,int pre) { int cnt=0; if(a[x]==1) siz[x] = 1; else siz[x] = 0; for(int i=h[x];i;i=nex[i]) if(to[i]!=pre) { dfs(to[i],x); if(siz[to[i]]>0) cnt++; siz[x] += siz[to[i]]; } if(m-siz[x]>=1) { if(!a[x]) ans += sum[x]-sum[pre]; else ans += max(sum[fa[x][0]]-sum[pre],0ll); } else if(cnt>=2 && !a[x]) ans += (x<=n); a[x] = h[x] = 0; } signed main() { cin>>Q; while(Q--) { memset(h,0,sizeof(h)), ee = 0; memset(dfn,0,sizeof(dfn)), memset(cut,0,sizeof(cut)); for(int i=1;i<=bcc;i++) c[i].clear(); bcc = 0; memset(sum,0,sizeof(sum)); cin>>n>>m; for(int i=1,x,y;i<=m&&scanf("%lld%lld",&x,&y);i++) addedge(x,y), addedge(y,x); for(int i=1;i<=n;i++) if(dfn[i]==0) tarjin(1,1); ee = 0, memset(h,0,sizeof(h)); for(int i=1;i<=bcc;i++) for(int j=0;j<c[i].size();j++) addedge(c[i][j],i+n), addedge(i+n,c[i][j]); memset(dfn,0,sizeof(dfn)); dfs0(1,0); ee = 0, memset(h,0,sizeof(h)); cin>>q; while(q--) { scanf("%lld",&m); for(int i=1;i<=m&&scanf("%lld",ls+i);i++) a[ls[i]]++; build(); ans = 0; dfs(1,0); printf("%lld\n",ans); } } return 0; }祝大家 AC 愉快!
-
0
#include<bits/stdc++.h> using namespace std; const int N=1e5+10;vector<int>G1[N],G2[N<<1]; int n,tsp,cnt,dfn[N<<1],low[N],a[N]; stack<int>stk; void tarjan(int x) { dfn[x]=low[x]=++tsp; stk.push(x); for(int y:G1[x]) { if(!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); if(dfn[x]==low[y]) { cnt++;G2[x].push_back(cnt); for(int z=-1;z!=y;) { z=stk.top();stk.pop(); G2[cnt].push_back(z); } } } else low[x]=min(low[x],dfn[y]); } } int D,dep[N<<1],d[N<<1],st[N<<1][18]; void dfs(int x,int xfa) { dfn[x]=++tsp;dep[x]=dep[xfa]+1; st[x][0]=xfa;for(int i=1;i<=D;i++)st[x][i]=st[st[x][i-1]][i-1]; for(int y:G2[x]) { d[y]=d[x]+(y<=n);dfs(y,x); } } int LCA(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=D;i>=0;i--)if(dep[st[x][i]]>=dep[y])x=st[x][i]; if(x==y) return x; for(int i=D;i>=0;i--)if(st[x][i]!=st[y][i])x=st[x][i],y=st[y][i]; return st[x][0]; } int main() { int T;scanf("%d",&T); while(T--) { int m;scanf("%d%d",&n,&m); memset(G1,0,sizeof(G1)); for(int i=1,x,y;i<=m;i++) { scanf("%d%d",&x,&y); G1[x].push_back(y);G1[y].push_back(x); } cnt=n; memset(G2,0,sizeof(G2)); tsp=0;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low)); tarjan(1),stk.pop(); tsp=0;D=log2(cnt); memset(dep,0,sizeof(dep));memset(st,0,sizeof(st));memset(d,0,sizeof(d)); dfs(1,0); int q;scanf("%d",&q); while(q--) { int k;scanf("%d",&k); for(int i=1;i<=k;i++)scanf("%d",&a[i]); sort(a+1,a+k+1,[](int x,int y){ return dfn[x]<dfn[y];}); int ans=0; for(int i=1,x,y;i<=k;i++) { x=a[i];y=a[i%k+1]; ans+=d[x]+d[y]-2*d[LCA(x,y)]; } if(LCA(a[k],a[1])<=n)ans+=2; printf("%d\n",ans/2-k); } } return 0; }
- 1
信息
- ID
- 2371
- 时间
- 10000ms
- 内存
- 512MiB
- 难度
- 8
- 标签
- 递交数
- 107
- 已通过
- 14
- 上传者