洛谷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 ...
随机推荐
- mysql批量新增的语法
?useUnicode=true//语序编码反射光hi &characterEncoding=UTF-8//字符 &autoReconnect=true//自动连接 &useA ...
- 《网页布局基础篇》HTML+CSS单列布局--水平居中,垂直居中,水平垂直居中
https://blog.csdn.net/panlu666_pl/article/details/66480433 一.水平居中 子元素在父元素中水平居中 1.使用 text-align和inlin ...
- VMware ESXi 7.0 U2 SLIC & Unlocker USB 网卡驱动集成镜像 202109更新
2021.08.31 更新:集成 "vmkusb-nic-fling"."net-community" 和 "nvme-community" ...
- vue系统总结2
注册组件 组件其他补充 组件数据存放 父子组件通信 父级向子级传递信息 子级向父级传递信息 插槽slot 1.1什么是组件化 1.2 注册组件的基本步骤 创建组件构造器 注册组件 使用组件 <d ...
- 【开发工具】Postman保姆级入门教程
目录 一.简单使用 1. 创建命名空间 2. 创建新集合 3. 按模块整理接口 二.使用环境变量 1. 创建环境与环境变量 2. 使用环境变量 3. 登录后自动更新环境变量 转载请注明出处 一.简单使 ...
- appium+python运行自动化测试提示“find_element() takes from 1 to 3 positional arguments but 14 were given”错误
1.运行后提示"find_element() takes from 1 to 3 positional arguments but 14 were given",在网上找了很多解决 ...
- chrome插件开发学习(一)
两个不错的网址: 360chrome插件开发文档:http://open.chrome.360.cn/extension_dev/manifest.html 图灵 chrome插件开发于应用 电子书: ...
- Walker
emmm.......随机化. 好吧,我们不熟. 考虑随机选取两组数据高斯消元消除结果后带入检验,能有超过1/2正确就输出. 其实方程就四个,手动解都没问题. 只是要注意看sin与 ...
- CSP-J&S 2020挂分记
应该是退役记 OI 是一门玄学--考后有感 Day -inf 找各科老师请假备考,看着我倒一倒二的好成绩分纷劝我放弃竞赛,成功请到了假. Day -1 怎么莫名其妙大家都在学些奇怪的东西? 跟风写了一 ...
- Appium问题解决方案(9)- Original error: Failed to launch Appium Settings app: Condition unmet after 5090 ms
背景 执行代码报错 解决方法 该问题并不常见,主要是手机操作系统的问题 程序无法无法自动打开appiumsettings,那么我们可以手动打开appiumsettings服务(程序没有界面,会出现打开 ...