【题解 P4606】战略游戏
[SDOI2018] 战略游戏
题目描述
省选临近,放飞自我的小 Q 无心刷题,于是怂恿小 C 和他一起颓废,玩起了一款战略游戏。
这款战略游戏的地图由
现在小 C 已经占领了其中至少两个城市,小 Q 可以摧毁一个小 C 没占领的城市,同时摧毁所有连接这个城市的道路。只要在摧毁这个城市之后能够找到某两个小 C 占领的城市
小 Q 和小 C 一共进行了
输入格式
第一行包含一个正整数
对于每组测试数据:
第一行是两个整数
接下来
第
接下来
输出格式
对于每一局游戏,输出一行,包含一个整数,表示这一局游戏中有多少个城市在小 Q 摧毁之后能够让他赢下这一局游戏。
样例 #1
样例输入 #1
2
7 6
1 2
1 3
2 4
2 5
3 6
3 7
3
2 1 2
3 2 3 4
4 4 5 6 7
6 6
1 2
1 3
2 3
1 4
2 5
3 6
4
3 1 2 3
3 1 2 6
3 1 5 6
3 4 5 6
样例输出 #1
0
1
3
0
1
2
3
提示
; 且 ; ;- 对于每组测试数据,有
。
Subtasks
- 子任务 1 (30 分):对于每组测试数据,满足
; - 子任务 2 (45 分):对于每一次询问,满足
; - 子任务 3 (25 分):没有任何附加的限制。
解法
看见删点后有两点不能到达,考虑割点。
看见
然后就是建一个圆方树,查询建虚树处理就好了。
但怎么查两点之间的割点数呢?
首先,若一个点为圆点(即不是点双造出来的点),他与父节点的连边的权值为1,否则为0。
设查询
还有是点转边,所以若联通块的根(
由于占领的点不能删,还有减去点的个数。
输出答案即可。
代码
#include<bits/stdc++.h>
using namespace std;
long long n,m,dfn[200005],low[100005],num,co,f[200005][19],deep[200005],f1[200005][19],val,m1,b[200005],r,d1[200005];
vector<long long> a[100005],d[200005],t[200005];
stack<long long> l;
bool v[200005];
void tarjan(long long x,long long y)
{
dfn[x]=low[x]=++num;
l.push(x);
for(int i=0;i<a[x].size();i++)
{
if(a[x][i]==y)continue;
if(!dfn[a[x][i]])
{
tarjan(a[x][i],x);
low[x]=min(low[x],low[a[x][i]]);
if(low[a[x][i]]>=dfn[x])
{
co++;
while(l.top()!=a[x][i])
{
d[co].push_back(l.top());
l.pop();
}
l.pop();
d[co].push_back(a[x][i]);
d[co].push_back(x);
}
}
else low[x]=min(low[x],dfn[a[x][i]]);
}
return;
}
void dfs1(long long x,long long y)
{
f[x][0]=y;
deep[x]=deep[y]+1;
dfn[x]=++num;
for(int i=0;i<t[x].size();i++)
{
if(t[x][i]==y)continue;
f1[t[x][i]][0]=v[t[x][i]];
dfs1(t[x][i],x);
}
return;
}
long long LCA(long long x,long long y)
{
if(deep[x]<deep[y])swap(x,y);
val=0;
for(int i=18;i>=0;i--)
{
if(deep[f[x][i]]>=deep[y])val+=f1[x][i],x=f[x][i];
}
if(x==y)return x;
for(int i=18;i>=0;i--)
{
if(f[x][i]!=f[y][i])val+=f1[x][i]+f1[y][i],x=f[x][i],y=f[y][i];
}
val+=f1[x][0]+f1[y][0];
x=f[x][0];
y=f[y][0];
return x;
}
bool cmp1(long long x,long long y)
{
return dfn[x]<dfn[y];
}
void poi()
{
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(f,0,sizeof(f));
memset(deep,0,sizeof(deep));
memset(f1,0,sizeof(f1));
memset(v,false,sizeof(v));
num=co=0;
long long x,y;
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%lld%lld",&x,&y);
a[x].push_back(y);
a[y].push_back(x);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])tarjan(i,0);
while(l.size()!=0)l.pop();
}
for(int i=1;i<=co;i++)
{
for(int j=0;j<d[i].size();j++)
{
t[n+i].push_back(d[i][j]);
t[d[i][j]].push_back(n+i);
}
}
for(int i=1;i<=n;i++)
{
v[i]=true;
}
num=0;
dfs1(1,0);
for(int i=1;i<=18;i++)
{
for(int j=1;j<=n+co;j++)f[j][i]=f[f[j][i-1]][i-1],f1[j][i]=f1[j][i-1]+f1[f[j][i-1]][i-1];
}
long long q,s;
scanf("%lld",&m);
for(int i=1;i<=m;i++)
{
s=0;
scanf("%lld",&m1);
for(int j=1;j<=m1;j++)
{
scanf("%lld",&b[j]);
}
sort(b+1,b+m1+1,cmp1);
for(int j=1;j<m1;j++)
{
LCA(b[j],b[j+1]);
s+=val;
}
LCA(b[1],b[m1]);
s+=val;
s/=2;
s+=v[LCA(b[1],b[m1])];
s-=m1;
printf("%lld\n",s);
}
for(int i=1;i<=n;i++)a[i].clear();
for(int i=1;i<=co;i++)d[i].clear();
for(int i=1;i<=co+n;i++)t[i].clear();
return;
}
int main()
{
long long qwe;
scanf("%lld",&qwe);
for(int i=1;i<=qwe;i++)poi();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧