洛谷4606 SDOI2018战略游戏(圆方树+虚树)
QWQ深受其害
当时在现场是真的绝望......
现在再重新来看这个题
QWQ
根据题目所说,我们可以发现,对于每一个集合中的节点,我们实际上就是要求两两路径上的割点的数目
考虑到又是关于点双的题目,而且在图上,我们并没有很好的办法去做。
这时候就要考虑建出来圆方树,然后我们对于圆方树 的每个点,维护他到根的路径上的圆点个数
那么,我们该怎么求两两路径的割点总数呢(一看到数据范围,就想到虚树了啊)
冷静分析一下,发现真的直接把虚树中的点弄出来就是合法的,因为两两的路径一定会通过\(lca\),而建出来虚树,正好只会保留有用的边。
那么我们对于虚树上的两个相连的点,他们的边权的就是两个点到根的圆点个数的差。
这里有一个关于虚树的
奇技淫巧
为了忽略\(1\)号节点对答案的影响,我们可以直接选择把所有关键点的\(lca\)放到虚树的栈里面当第一个元素,而不是1
最后对于一次询问,我们只需要求虚树的边权和即可(还需要特判根的问题)
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk makr_pair
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 4e5+1e2;
const int maxm = 2*maxn;
int point[maxn],nxt[maxm],to[maxm];
int point1[maxn],nxt1[maxm],to1[maxm];
int cnt,cnt1;
int n,m;
int dfn[maxn],deep[maxn],low[maxn];
int f[maxn][20];
int st[maxn],tot,top;
int num;
int a[maxn],k;
int dnf[maxn],size[maxn];
void addedge1(int x,int y)
{
nxt1[++cnt1]=point1[x];
to1[cnt1]=y;
point1[x]=cnt1;
}
void addedge(int x,int y)
{
nxt[++cnt]=point[x];
to[cnt]=y;
point[x]=cnt;
}
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++tot;
st[++top]=x;
for (int i=point1[x];i;i=nxt1[i])
{
int p=to1[i];
if (p==fa) continue;
if (!dfn[p])
{
tarjan(p,x);
low[x]=min(low[x],low[p]);
if (low[p]>=dfn[x])
{
num++;
addedge(num,x);
addedge(x,num);
do{
addedge(num,st[top]);
addedge(st[top],num);
top--;
}while (st[top+1]!=p);
}
}
else low[x]=min(low[x],dfn[p]);
}
}
int tmp;
void dfs(int x,int fa,int dep)
{
int now=0;
if (x<=n) now++;
deep[x]=dep;
dnf[x]=++tmp;
size[x]=size[fa]+now;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if(p==fa) continue;
f[p][0]=x;
dfs(p,x,dep+1);
}
}
void init()
{
for (int j=1;j<=19;j++)
for (int i=1;i<=num;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
}
}
int go_up(int x,int d)
{
for (int i=0;i<=19;i++)
{
if ((1<<i) & d) x=f[x][i];
}
return x;
}
int lca(int x,int y)
{
if(deep[x]>deep[y]) x=go_up(x,deep[x]-deep[y]);
else y=go_up(y,deep[y]-deep[x]);
if (x==y) return x;
for (int i=19;i>=0;i--)
{
if (f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
bool cmp(int a,int b)
{
return dnf[a]<dnf[b];
}
struct xvtree{
int point[maxn],nxt[maxm],to[maxm];
int val[maxm];
int cnt;
int s[maxn],top;
int sum;
void init()
{
cnt=0;
sum=0;
}
void addedge(int x,int y,int w)
{
//cout<<x<<" ** "<<y<<" "<<w<<endl;
nxt[++cnt]=point[x];
to[cnt]=y;
val[cnt]=w;
point[x]=cnt;
}
void dfs(int x,int fa)
{
for (int &i=point[x];i;i=nxt[i])
{
int p = to[i];
if (p==fa) continue;
sum+=val[i];
dfs(p,x);
}
}
int solve()
{
init();
top=1;
sort(a+1,a+1+k,cmp);
int root=a[1];
for (int i=2;i<=k;i++) root=lca(root,a[i]);
s[top]=root;
for (int i=1;i<=k;i++)
{
int l = lca(s[top],a[i]);
if (l!=s[top])
{
while (top>1)
{
if (dnf[s[top-1]]>dnf[l])
{
addedge(s[top-1],s[top],size[s[top]]-size[s[top-1]]);//size表示他在圆方树上和根的路径上的圆点个数
top--;
}
else
{
if (dnf[s[top-1]]==dnf[l])
{
addedge(s[top-1],s[top],size[s[top]]-size[s[top-1]]);
top--;
break;
}
else
{
addedge(l,s[top],size[s[top]]-size[l]);
s[top]=l;
break;
}
}
}
}
if (s[top]!=a[i]) s[++top]=a[i];
}
while (top>1)
{
addedge(s[top-1],s[top],size[s[top]]-size[s[top-1]]);
top--;
}
dfs(root,0);
if(root<=n) sum++;
return sum;
}
};
xvtree xv;
int t;
int main()
{
t=read();
while (t--)
{
tmp=0;tot=0;top=0;
cnt=0;cnt1=0;
xv.init();
memset(point,0,sizeof(point));
memset(point1,0,sizeof(point1));
memset(f,0,sizeof(f));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(dnf,0,sizeof(dnf));
n=read(),m=read();
num=n;
for (int i=1;i<=m;i++)
{
int x=read(),y=read();
addedge1(x,y);
addedge1(y,x);
}
for (int i=1;i<=n;i++)
{
if (!dfn[i]) tarjan(i,0);
}
dfs(1,0,1);
init();
int q=read();
for (int i=1;i<=q;i++)
{
k=read();
for (int j=1;j<=k;j++) a[j]=read();
xv.init();
cout<<xv.solve()-k<<"\n";
}
}
return 0;
}
洛谷4606 SDOI2018战略游戏(圆方树+虚树)的更多相关文章
- bzoj5315/luoguP4517 [SDOI2018]战略游戏(圆方树,虚树)
bzoj5315/luoguP4517 [SDOI2018]战略游戏(圆方树,虚树) bzoj Luogu 题目描述略(太长了) 题解时间 切掉一个点,连通性变化. 上圆方树. $ \sum |S| ...
- [SDOI2018]战略游戏 圆方树,树链剖分
[SDOI2018]战略游戏 这题是道路相遇(题解)的升级版,询问的两个点变成了\(S\)个点. LG传送门 还是先建出圆方树,考虑对于询问的\(S\)个点,答案就是圆方树上能包含这些点的最小连通块中 ...
- 洛谷P4606 [SDOI2018]战略游戏 【圆方树 + 虚树】
题目链接 洛谷P4606 双倍经验:弱化版 题解 两点之间必经的点就是圆方树上两点之间的圆点 所以只需建出圆方树 每次询问建出虚树,统计一下虚树边上有多少圆点即可 还要讨论一下经不经过根\(1\)的情 ...
- 洛谷P4606 [SDOI2018]战略游戏 [广义圆方树]
传送门 思路 先考虑两点如何使他们不连通. 显然路径上所有的割点都满足条件. 多个点呢?也是这样的. 于是可以想到圆方树.一个点集的答案就是它的虚树里圆点个数减去点集大小. 可以把点按dfs序排序,然 ...
- BZOJ5329:[SDOI2018]战略游戏(圆方树,虚树)
Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着 ...
- Luogu4606 SDOI2018 战略游戏 圆方树、虚树、链并
传送门 弱化版 考虑到去掉一个点使得存在两个点不连通的形式类似割点,不难想到建立圆方树.那么在圆方树上对于给出的关键点建立虚树之后,我们需要求的就是虚树路径上所有圆点的数量减去关键点的数量. 因为没有 ...
- Luogu P4606 [SDOI2018] 战略游戏 圆方树 虚树
https://www.luogu.org/problemnew/show/P4606 把原来的图的点双联通分量缩点(每个双联通分量建一个点,每个割点再建一个点)(用符合逻辑的方式)建一棵树(我最开始 ...
- BZOJ.5329.[SDOI2018]战略游戏(圆方树 虚树)
题目链接 显然先建圆方树,方点权值为0圆点权值为1,两点间的答案就是路径权值和减去起点终点. 对于询问,显然可以建虚树.但是只需要计算两关键点间路径权值,所以不需要建出虚树.统计DFS序相邻的两关键点 ...
- 洛谷P4630 铁人两项--圆方树
一道很好的圆方树入门题 感谢PinkRabbit巨佬的博客,讲的太好啦 首先是构建圆方树的代码,也比较好想好记 void tarjan(int u) { dfn[u] = low[u] = ++dfn ...
随机推荐
- Django的基本运用(垃圾分类)
title: 利用Django实现一个能与用户交互的初级框架 author: Sun-Wind date: September 1, 2021 Django实现基本的框架 此框架的功能是搭建服务器,使 ...
- 基于CentOS7.x Linux操作系统,从0开始构建一套Docker虚拟化平台,使用二进制Tar包方式,部署的步骤和方法如下:
#配置centos7的yum源#建议阿里源#链接:https://yq.aliyun.com/articles/525282?type=2#从Docker官网下载软件包: ls -l docker-1 ...
- 图解最长回文子串「Manacher 算法」,基础思路感性上的解析
问题描述: 给你一个字符串 s,找到 s 中最长的回文子串. 链接:https://leetcode-cn.com/problems/longest-palindromic-substring 「Ma ...
- Django自带评论功能的基本使用
1. 模块安装 pip install django-contrib-comments 2. 注册APP INSTALLED_APP=( #..., 'django_comments', 'djang ...
- 机器学习之支持向量机(python)
参考链接:https://blog.csdn.net/weixin_33514582/article/details/113321749.https://blog.csdn.net/weixin_44 ...
- ubantu硬盘不足,无法启动
我的ubantu虚拟机经过我一顿操作后,就起不来了.然后经过多方询问,广集天下良方,最终发现是由于分配的硬件空间不足导致的.现象如下: 通过查看 root@ubantu:/snap# df -h Fi ...
- Golang入门学习(三):函数
文章目录 2.3 函数 2.3.1 基本语法 2.3.2 入门demo: 2.3.3 函数递归: 2.3.4 函数注意事项 2.3.5 init函数 2.3.6 匿名函数 2.3.7 闭包 2.3.8 ...
- ipsec.conf配置文件多个保护子网解析流程
Author : Email : vip_13031075266@163.com Date : 2021.01.23 Copyright : 未经同意不得 ...
- LayoutControl控件使用
因默认外边距过大需要将外边距缩小用以下代码实现layoutControlGroup1.Padding = DevExpress.XtraLayout.Utils.Padding.Empty;是否允许只 ...
- (4)java Spring Cloud+Spring boot+mybatis企业快速开发架构之SpringCloud-Spring Cloud开发环境的准备和Lombok安装步骤
开发环境的准备主要涉及三个方面:JDK.Maven.Spring Tools 4 for Eclipse. 1.JDK JDK 的版本用 1.8 即可,环境变量大家自行去配置.配置好环境变量,在命 ...