Luogu P4606 [SDOI2018] 战略游戏 圆方树 虚树
https://www.luogu.org/problemnew/show/P4606
把原来的图的点双联通分量缩点(每个双联通分量建一个点,每个割点再建一个点)(用符合逻辑的方式)建一棵树(我最开始建的想法就有问题,答案竟然还差不多,查了好久才发现……然后重新想了个正确的建法发现比之前那个错误的建法好写多了,气),然后把这棵树整成虚树再做个树上dp就(安排得)明明白白的了。dp的时候注意一下树的根的值也要统计。
我的程序大概常数太大了洛谷开O2才能过,BZOJ会tle,也不想改了,就这样吧……
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=;
int n,m;
struct nod{
int y,next;
};nod e1[maxn*];nod e[maxn*];nod e2[maxn*];
int head1[maxn]={},head[maxn]={},tot1=,tot=;
int head2[maxn]={},tot2=;
int dfn[maxn]={},low[maxn]={},bel[maxn]={},bel1[maxn]={},poi[maxn]={},sta[maxn]={},tai,cnt,tn;
int val[maxn]={};
int pa[maxn]={};
void init1(int x,int y){ e1[++tot1].y=y;e1[tot1].next=head1[x];head1[x]=tot1; }
void init(int x,int y){ e[++tot].y=y;e[tot].next=head[x];head[x]=tot; }
void init2(int x,int y){ e2[++tot2].y=y;e2[tot2].next=head2[x];head2[x]=tot2; }
int getpa(int x){return x==pa[x]?x:getpa(pa[x]);}
void merpa(int x,int y){
x=getpa(x);y=getpa(y);
pa[x]=pa[y];
}
void Tarjan(int x,int p){
dfn[x]=low[x]=++cnt;sta[++tai]=x; int z=;
for(int i=head1[x];i;i=e1[i].next){
if(e1[i].y==p)continue;
if(!dfn[e1[i].y]){
Tarjan(e1[i].y,x);
low[x]=min(low[e1[i].y],low[x]);
if(low[e1[i].y]>=dfn[x]){
int w; ++tn;++z;
if(low[e1[i].y]==dfn[x]&&!p)bel[x]=tn;
do{
w=sta[tai--];
bel[w]=tn;
}while(w!=e1[i].y);
}
}
else low[x]=min(low[x],dfn[e1[i].y]);
}
if(z>=&&p){
poi[x]=;
bel1[x]=++tn;
}
if(!p){
if(z>){poi[x]=;bel1[x]=++tn;}
if(!bel[x])bel[x]=++tn;
}
}
void dfs1(int x){
for(int i=head1[x];i;i=e1[i].next){
int y=e1[i].y;
if(poi[y]){
if(getpa(bel1[y])!=getpa(bel[x])){
init(bel1[y],bel[x]);init(bel[x],bel1[y]);
merpa(bel1[y],bel[x]);
}
}
}
}
void dfs11(int x){
for(int i=head1[x];i;i=e1[i].next){
int y=e1[i].y;
if(poi[y]){
if(getpa(bel1[y])!=getpa(bel1[x])){
init(bel1[y],bel1[x]);init(bel1[x],bel1[y]);
merpa(bel1[y],bel1[x]);
}
}
}
}
int dep[maxn]={},fa[maxn][]={},id[maxn]={},shu;
int a[maxn]={},val1[maxn];
void dfs(int x,int p){
dep[x]=dep[p]+;fa[x][]=p;val[x]=val[p]+val1[x];id[x]=++shu;
//cout<<x<<shu<<endl;
for(int i=;i<=;i++)fa[x][i]=fa[fa[x][i-]][i-];
for(int i=head[x];i;i=e[i].next){
if(e[i].y==p)continue;
dfs(e[i].y,x);
}
}
bool mcmp(int x,int y){
return id[x]<id[y];
}
int getlca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
if(dep[x]!=dep[y])for(int i=;i>=;i--)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
if(x==y)return x;
for(int i=;i>=;i--)if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];}
return fa[x][];
}
int dfs2(int x){
int ans=;//cout<<x<<endl;
for(int i=head2[x];i;i=e2[i].next){//cout<<x<<e2[i].y<<endl;
ans+=dfs2(e2[i].y);
ans+=val[e2[i].y]-val[x];
}
return ans;
}
void dfs3(int x){
for(int i=head2[x];i;i=e2[i].next){
dfs3(e2[i].y);
}head2[x]=;
}
void solve(){
int nm;scanf("%d",&nm);
int tly=,w=;
for(int i=;i<=nm;i++){ scanf("%d",&a[i]); if(poi[a[i]]){a[i]=bel1[a[i]]; }else a[i]=bel[a[i]];}
sort(a+,a++nm,mcmp);
for(int i=;i<=nm;i++)if(a[tly]!=a[i])a[++tly]=a[i];
tot2=;tai=;sta[]=a[];w-=val1[a[]];
for(int i=;i<=tly;i++){
int lc=getlca(sta[tai],a[i]);w-=val1[a[i]];//cout<<a[i]<<sta[tai]<<lc<<endl;
while(tai&&dep[lc]<dep[sta[tai]]){
if(tai==||(tai>&&dep[sta[tai-]]<dep[lc])){
init2(lc,sta[tai]);tai--;break;
}
if(tai->)init2(sta[tai-],sta[tai]);
tai--;
}
if(sta[tai]!=lc||!tai)sta[++tai]=lc;
if(sta[tai]!=a[i]||!tai)sta[++tai]=a[i];
}
while(--tai){init2(sta[tai],sta[tai+]);}
w+=dfs2(sta[]); dfs3(sta[]);
//cout<<tly<<' '<<a[1]<<' '<<a[2]<<endl;
//cout<<sta[1]<<' '<<getlca(a[1],a[2])<<endl;
w+=val1[sta[]];
cout<<w<<endl;
}
int main(){
//freopen("game.in","r",stdin);
//freopen("game.out","w",stdout);
int T;scanf("%d",&T);
while(T-->){
scanf("%d%d",&n,&m);
memset(dfn,,sizeof(dfn));
memset(poi,,sizeof(poi));
memset(low,,sizeof(low));
memset(bel,,sizeof(bel));
memset(bel1,,sizeof(bel1));
memset(head1,,sizeof(head1));
memset(head2,,sizeof(head2));
memset(head,,sizeof(head));
memset(fa,,sizeof(fa));
memset(val,,sizeof(val));
memset(val1,,sizeof(val1));
tot1=,tot2=,tot=;cnt=;tn=;tai=;shu=;
int x,y;
for(int i=;i<=m;i++){scanf("%d%d",&x,&y);if(x==y)continue;init1(x,y);init1(y,x);}
Tarjan(,);for(int i=;i<=tn;i++)pa[i]=i;
for(int i=;i<=n;i++){
if(poi[i]){
val1[bel1[i]]=;
if(getpa(bel[i])!=getpa(bel1[i])){init(bel[i],bel1[i]);init(bel1[i],bel[i]);merpa(bel1[i],bel[i]);}
}else dfs1(i);
/*cout<<bel[i]<<bel1[i]<<poi[i]<<endl;*/
}
for(int i=;i<=n;i++){
if(poi[i])dfs11(i);
}
dfs(,);
int q;scanf("%d",&q);
for(int i=;i<=q;i++)solve();
}
return ;
}
Luogu P4606 [SDOI2018] 战略游戏 圆方树 虚树的更多相关文章
- bzoj5315/luoguP4517 [SDOI2018]战略游戏(圆方树,虚树)
bzoj5315/luoguP4517 [SDOI2018]战略游戏(圆方树,虚树) bzoj Luogu 题目描述略(太长了) 题解时间 切掉一个点,连通性变化. 上圆方树. $ \sum |S| ...
- [SDOI2018]战略游戏 圆方树,树链剖分
[SDOI2018]战略游戏 这题是道路相遇(题解)的升级版,询问的两个点变成了\(S\)个点. LG传送门 还是先建出圆方树,考虑对于询问的\(S\)个点,答案就是圆方树上能包含这些点的最小连通块中 ...
- BZOJ5329:[SDOI2018]战略游戏(圆方树,虚树)
Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着 ...
- Luogu4606 SDOI2018 战略游戏 圆方树、虚树、链并
传送门 弱化版 考虑到去掉一个点使得存在两个点不连通的形式类似割点,不难想到建立圆方树.那么在圆方树上对于给出的关键点建立虚树之后,我们需要求的就是虚树路径上所有圆点的数量减去关键点的数量. 因为没有 ...
- BZOJ.5329.[SDOI2018]战略游戏(圆方树 虚树)
题目链接 显然先建圆方树,方点权值为0圆点权值为1,两点间的答案就是路径权值和减去起点终点. 对于询问,显然可以建虚树.但是只需要计算两关键点间路径权值,所以不需要建出虚树.统计DFS序相邻的两关键点 ...
- luogu P4606 [SDOI2018]战略游戏
LINK:战略游戏 一道很有价值的题目.这道题 一张无向联通图 每次询问给出K个关键点 问摧毁图中哪个点可以使得这K个关键的两两之间有一对不能联通 去掉的这个点不能是关键点 求方案数. 可以发现 当K ...
- [bzoj5329] P4606 [SDOI2018]战略游戏
P4606 [SDOI2018]战略游戏:广义圆方树 其实会了圆方树就不难,达不到黑,最多算个紫 那个转换到圆方树上以后的处理方法,画画图就能看出来,所以做图论题一定要多画图,并把图画清楚点啊!! 但 ...
- 洛谷P4606 [SDOI2018]战略游戏 【圆方树 + 虚树】
题目链接 洛谷P4606 双倍经验:弱化版 题解 两点之间必经的点就是圆方树上两点之间的圆点 所以只需建出圆方树 每次询问建出虚树,统计一下虚树边上有多少圆点即可 还要讨论一下经不经过根\(1\)的情 ...
- 洛谷P4606 [SDOI2018]战略游戏 [广义圆方树]
传送门 思路 先考虑两点如何使他们不连通. 显然路径上所有的割点都满足条件. 多个点呢?也是这样的. 于是可以想到圆方树.一个点集的答案就是它的虚树里圆点个数减去点集大小. 可以把点按dfs序排序,然 ...
随机推荐
- http Get和Post请求方式
string postURL ="http://xxxxx.ashx"; List<string> paramName = new List<string&g ...
- 转载-struts中logic标签使用
Struts中Logic逻辑标签的作用及用法 Struts中Logic逻辑标签的作用及用法 2006年10月18日 星期三 21:34 Terry原创,转载请说明作者及出处 Logic标签大部分的功能 ...
- 移动端测试=== adb 无线连接手机
无线连接(需要借助 USB 线) 除了可以通过 USB 连接设备与电脑来使用 adb,也可以通过无线连接——虽然连接过程中也有需要使用 USB 的步骤,但是连接成功之后你的设备就可以在一定范围内摆脱 ...
- linux下pip安装无法连接官网
为了安装pwntools等工具,要先安装pip,系统安装好了,却遇到了无法连接到pip官网的报错,找了半天方法最终解决 wget https://bootstrap.pypa.io/get-pip.p ...
- 关于Java中final关键字的详细介绍
Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用final的好处是什么?最后也有一些使 ...
- qt使用动态库(DLL)
本文主要讲解在QT开发环境中如何使用VC生成的DLL及QT自身生成的DLL.至于其它情况本文不作讨论. 连接库分为2种 (1)动态连接库,通常有.h .lib .dll三个文件,功能实现在dll中 ( ...
- 理解 Linux 的硬链接与软链接(待研究)
从 inode 了解 Linux 文件系统 硬链接与软链接是 Linux 文件系统中的一个重要概念,其涉及文件系统中的索引节点 (index node 又称 inode),而索引节点对象是 Linux ...
- 使用UDP和TCP协议的各种应用和应用层协议
IGMP和ICMP是传输层协议
- Flask:文件配置方式实践及其中的各种问题记录
Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2, 提示: 1.请查看本文后面的“18-07-17 11:18重大纠正” ! 2.flask run命令运行时传入参数 ...
- Python开发环境(3):使用Eclipse+PyDev插件创建Django项目
OS:Windows 10家庭中文版,Python:3.6,Eclipse:Oxygen.1a Release (4.7.1a), PyDev:6.3.2,Django:2.0.3 本文展示了怎么使用 ...