题目描述

省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏。
这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着道路走到
任意其他城市。现在小C已经占领了其中至少两个城市,小Q可以摧毁一个小C没占领的城市,同时摧毁所有连接这
个城市的道路。只要在摧毁这个城市之后能够找到某两个小C占领的城市u和v,使得从u出发沿着道路无论如何都不
能走到v,那么小Q就能赢下这一局游戏。
小Q和小C一共进行了q局游戏,每一局游戏会给出小C占领的城市集合S
你需要帮小Q数出有多少个城市在他摧毁之后能够让他赢下这一局游戏。
题解
如果这是一棵树,那么做法就是直接对询问点见虚树,统计包含树中的点的最小联通块的大小。
现在它是一张无向图,那么就把圆方树建出来,考虑一条路径经过了圆->方->圆点,那么那两个圆点割点,应对答案有1的贡献,方点的贡献为0。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#define N 200009
using namespace std;
typedef long long ll;
int dfn[N],head[N],tot,dis[N],n,low[N],ans,num,st[N],top,rbs[N],a[N];
bool vis[N];
inline ll rd(){ll x=0;char c=getchar();bool f=0;while(!isdigit(c)){if(c=='-')f=1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}return f?-x:x;
}
struct edge{int n,to;}e[N<<1];
inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
vector<int>vec[N],ed[N];
inline bool cmp(int a,int b){return dfn[a]<dfn[b];}
struct LCA{
int top[N],size[N],son[N],fa[N],deep[N];
void clear(){memset(deep,0,sizeof(deep));memset(top,0,sizeof(top));memset(son,0,sizeof(son));memset(fa,0,sizeof(fa));}
void dfs(int u){size[u]=1;dis[u]=dis[fa[u]]+(u<=n);for(int i=0;i<vec[u].size();++i){int v=vec[u][i];fa[v]=u;deep[v]=deep[u]+1;dfs(v);size[u]+=size[v];if(size[v]>size[son[u]])son[u]=v;}
}
void dfs2(int u){dfn[u]=++dfn[0];if(!top[u])top[u]=u;if(son[u])top[son[u]]=top[u],dfs2(son[u]);for(int i=0;i<vec[u].size();++i){int v=vec[u][i];if(v!=fa[u]&&v!=son[u])dfs2(v);}
}
inline int getlca(int u,int v){while(top[u]!=top[v]){if(deep[top[u]]<deep[top[v]])swap(u,v);u=fa[top[u]];}return deep[u]<deep[v]?u:v;
}
}lca;
void tarjan(int u,int fa){dfn[u]=low[u]=++dfn[0];vis[u]=1;st[++top]=u;for(int i=head[u];i;i=e[i].n)if((i^fa)!=1){int v=e[i].to;if(dfn[v]>dfn[u])continue;if(!dfn[v]){tarjan(v,i);low[u]=min(low[u],low[v]);}else if(vis[v])low[u]=min(low[u],dfn[v]);if(dfn[u]==low[v]){++num;vec[u].push_back(num);//cout<<u<<" "<<num<<endl;while(st[top]!=v){vec[num].push_back(st[top]);//cout<<num<<" "<<st[top]<<endl;vis[st[top]]=0;top--;}vec[num].push_back(v);vis[v]=0;top--;//cout<<num<<" "<<v<<endl;
        }if(low[v]>dfn[u]){vec[u].push_back(v);top--;vis[v]=0;}}
}
void dfs(int u){for(int i=0;i<ed[u].size();++i){int v=ed[u][i];dfs(v);ans+=dis[v]-dis[u]; if(vis[v]&&v<=n)ans--;}
}
inline void init(){tot=1;top=0;memset(head,0,sizeof(head));memset(dfn,0,sizeof(dfn));memset(dis,0,sizeof(dis));lca.clear();
}
inline void solve(){n=rd();int m=rd();int u,v;init();for(int i=1;i<=m;++i){u=rd();v=rd();add(u,v);add(v,u);} num=n;tarjan(1,0);memset(dfn,0,sizeof(dfn));top=0;lca.dfs(1);lca.dfs2(1);memset(vis,0,sizeof(vis));int q=rd();while(q--){int s=rd();ans=0;for(int i=1;i<=s;++i)a[i]=rd(),vis[a[i]]=1;sort(a+1,a+s+1,cmp);st[top=1]=rbs[rbs[0]=1]=a[1];int root=a[1];for(int i=2;i<=s;++i){int x=a[i];//cout<<x<<"guiu"<<endl;int l=lca.getlca(x,st[top]);if(l==st[top]){st[++top]=x;rbs[++rbs[0]]=x;continue;}while(top>1){int xx=st[top],yy=st[top-1];if(dfn[yy]<=dfn[l]){ed[l].push_back(xx);//cout<<l<<" "<<xx<<endl;top--;break;}ed[yy].push_back(xx);top--;//cout<<yy<<" "<<xx<<endl;
            }if(dfn[l]<dfn[st[top]]){if(dfn[l]<dfn[root])root=l;//    cout<<l<<" "<<st[top]<<endl;ed[l].push_back(st[top]);top--;}if(l!=st[top])st[++top]=l,rbs[++rbs[0]]=l;st[++top]=x;rbs[++rbs[0]]=x; }while(top>1){//    cout<<st[top-1]<<" "<<st[top]<<endl;ed[st[top-1]].push_back(st[top]);top--;}if(!vis[root]&&root<=n)ans++;dfs(root);printf("%d\n",ans);while(rbs[0]){int x=rbs[rbs[0]];vis[x]=0;ed[x].clear();rbs[0]--;}        } for(int i=1;i<=num;++i)vec[i].clear();
}
int main(){int T=rd();while(T--)solve();return 0;
} 

这里的圆方树不能随便的建,只能对每个点双开一个。、

具体建法为:对于非点双内的边,直接连,并且弹栈。

    if(low[v]>dfn[u]){vec[u].push_back(v);top--;vis[v]=0;}

对于每个割顶,新开一个节点,然后边弹栈边连边。

if(dfn[u]==low[v]){++num;vec[u].push_back(num);while(st[top]!=v){vec[num].push_back(st[top]);vis[st[top]]=0;top--;}vec[num].push_back(v);vis[v]=0;top--;}

而且我们对于每个点双都只能算一次,为了避免算重,我们需要特判一下。

if(dfn[v]>dfn[u])continue

转载于:https://www.cnblogs.com/ZH-comld/p/10384724.html

[SDOI2018]战略游戏相关推荐

  1. LuoguP4606 [SDOI2018]战略游戏

    LuoguP4606 [SDOI2018]战略游戏 题目描述 题目描述 省选临近,放飞自我的小 QQ 无心刷题,于是怂恿小 CC 和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由 nn 个城市 ...

  2. [BZOJ5329][Sdoi2018]战略游戏 圆方树+虚树

    5329: [Sdoi2018]战略游戏 Time Limit: 30 Sec  Memory Limit: 512 MB Submit: 174  Solved: 109 [Submit][Stat ...

  3. BZOJ5329: [SDOI2018]战略游戏——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=5329 https://www.luogu.org/problemnew/show/P4606 省选 ...

  4. BZOJ5329:[SDOI2018]战略游戏(圆方树,虚树)

    Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着 ...

  5. [BZOJ5329][SDOI2018]战略游戏

    bzoj luogu Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任 ...

  6. Luogu4606 SDOI2018 战略游戏 圆方树、虚树、链并

    传送门 弱化版 考虑到去掉一个点使得存在两个点不连通的形式类似割点,不难想到建立圆方树.那么在圆方树上对于给出的关键点建立虚树之后,我们需要求的就是虚树路径上所有圆点的数量减去关键点的数量. 因为没有 ...

  7. 【题解】SDOI2018战略游戏

    被CNST的大小卡了好久.一定要开到18呀-- 首先,遇到这种带各种各样环的图先考虑是不是可以建立圆方树,在圆方树上求出答案.然后转化为圆方树之后,我们就将图转化到了树上.答案非常的明显:只要一个圆点 ...

  8. P4606 [SDOI2018]战略游戏

    [题意] 给出一个无向图,q次询问,每次给定一个点集s代表占领点,问有多少个未被占领的点可以作为点集s中两个点u,v的割点 [分析] 首先,先建立圆方树,问题转化为能包含 给定点集 的最小连通块的 圆 ...

  9. [SDOI2018]战略游戏 圆方树+虚树

    Description 给T组数据. 每组数据给你一个n个点的无向图,保证图联通,给q个询问. 每个询问给k个节点,问每一次询问中,求有多少个点在断掉他之后可以使图中两个点不连通. Sample In ...

最新文章

  1. 2022 AI趋势8大预测!
  2. [转载]offsetHeight , clientHeight, scrollHeight 区别
  3. c++笔试题两道,求解当中一道
  4. [Google Guava] 7-原生类型
  5. 汽车车牌识别系统(六)-- 项目中的各个文件解析
  6. 算法优化:最大字段和,双指针遍历(n^2),分治法(nlogn),动态规划(n)
  7. js 获取td高度_JS或jQuery获取宽高度
  8. 基于位置的知识图谱链接预测
  9. oralce 11g rac ocr和votedisk迁移
  10. 笔者使用macOS的一些经验点滴记录1
  11. paip.hibernate list 返回位null的解决
  12. java 单元测试 网络请求_Spring Boot 系列(二)单元测试网络请求
  13. 小学steam计算机课程案例,STEAM课程典型案例——桥世界
  14. python列表姓氏_Python 批量生成中文姓名(百家姓)
  15. Maven创建一个Servlet项目(五)
  16. pip install使用豆瓣库
  17. 吉大17秋计算机应用二,吉大17秋《计算机应用基础》在线作业二.doc
  18. 关于进程,线程,协程,一点心得
  19. 如何一下清空微信好友_微信通讯录中的好友,怎样全部删除?
  20. c语言的七大查找算法,非常值得学习

热门文章

  1. springmvc结合thymeleaf的使用(项目搭建)
  2. AM335X的汇编语言与c语言,AM335x的PRUSSv2简介与使用
  3. HTML5 Web 开发培训讲义
  4. 模数(A/D)转换器工作原理
  5. ldap运维中遇到的问题
  6. 2021年计算机保研-假211真双非三无的失败保研经历(武大/复旦/计算所/华科/同济/上交)
  7. 头条号自媒体运营技巧,百万爆文运营经验分享
  8. 总结49种软件测试方法,你知道几个?
  9. 为什么赛车前轮不按照阿克曼转角设计?
  10. win10 win+空格切换输入法;win10删除微软输入法2021-5-5