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序排序,然 ...
随机推荐
- Jetson TX1 安装Kinect驱动
1.添加Universe源 $ sudo apt-add-repository universe $ sudo apt-get update 2.安装编译工具和依赖项 $ sudo apt-get i ...
- 【CTF WEB】文件包含
文件包含 题目要求: 请找到题目中FLAG 漏洞源码 <meta charset='utf-8'> <center><h1>文件阅读器</h1>< ...
- MySQL主从复制-指定数据库复制
在/etc/my.cnf添加需要进行同步的数据库信息 #需要进行同步的数据库 #replicate-do-db=custmgr #replicate-do-db=sdata #replicate-ig ...
- liunx系统top命令详解
ps: 1.按1可以进行 CPU各个和总CPU汇总的切换2.cpu0是最关键的,总控管理各个CPU 3.默认情况下仅显示比较重要的 PID.USER.PR.NI.VIRT.RES.SHR.S.%CPU ...
- 【C语言学习笔记】字符串拼接的3种方法 .
昨天晚上和@buptpatriot讨论函数返回指针(malloc生成的)的问题,提到字符串拼接,做个总结. #include<stdio.h> #include<stdlib.h&g ...
- SpringMVC 返回JSON数据的配置
spring-mvc-config.xml(文件名称请视具体情况而定)配置文件: <!-- 启动Springmvc注解驱动 --> <mvc:annotation-driven> ...
- 3.Springboot之修改启动时的默认图案Banner
一.SpringBoot的默认启动图案 在SpringBoot启动的时候,默认的会展示出一个spring的logo,这个图案我们用户是可以自定义的 二.自定义启动图案 方法一: Application ...
- 洛谷P3378堆
传送门啦 #include <iostream> #include <cstdio> #include <cstring> #include <algorit ...
- Jenkins 集成 Sonar
Jenkins 与 Sonar 集成:Sonar 是 Jenkins 之外独立运行的一个服务.Jenkins 中安装插件 SonarQube(并配置其 Sonar Server 的 URL / Acc ...
- 函数fgets和fputs、fread和fwrite用法小结(转)
字符串读写函数fgets和fputs: 1.fgets()函数:原型char *fgets(char *s, int n, FILE *stream);从流中读取n-1(n默认1024)个字符之前,如 ...