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] 战略游戏 圆方树 虚树的更多相关文章

  1. bzoj5315/luoguP4517 [SDOI2018]战略游戏(圆方树,虚树)

    bzoj5315/luoguP4517 [SDOI2018]战略游戏(圆方树,虚树) bzoj Luogu 题目描述略(太长了) 题解时间 切掉一个点,连通性变化. 上圆方树. $ \sum |S| ...

  2. [SDOI2018]战略游戏 圆方树,树链剖分

    [SDOI2018]战略游戏 这题是道路相遇(题解)的升级版,询问的两个点变成了\(S\)个点. LG传送门 还是先建出圆方树,考虑对于询问的\(S\)个点,答案就是圆方树上能包含这些点的最小连通块中 ...

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

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

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

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

  5. BZOJ.5329.[SDOI2018]战略游戏(圆方树 虚树)

    题目链接 显然先建圆方树,方点权值为0圆点权值为1,两点间的答案就是路径权值和减去起点终点. 对于询问,显然可以建虚树.但是只需要计算两关键点间路径权值,所以不需要建出虚树.统计DFS序相邻的两关键点 ...

  6. luogu P4606 [SDOI2018]战略游戏

    LINK:战略游戏 一道很有价值的题目.这道题 一张无向联通图 每次询问给出K个关键点 问摧毁图中哪个点可以使得这K个关键的两两之间有一对不能联通 去掉的这个点不能是关键点 求方案数. 可以发现 当K ...

  7. [bzoj5329] P4606 [SDOI2018]战略游戏

    P4606 [SDOI2018]战略游戏:广义圆方树 其实会了圆方树就不难,达不到黑,最多算个紫 那个转换到圆方树上以后的处理方法,画画图就能看出来,所以做图论题一定要多画图,并把图画清楚点啊!! 但 ...

  8. 洛谷P4606 [SDOI2018]战略游戏 【圆方树 + 虚树】

    题目链接 洛谷P4606 双倍经验:弱化版 题解 两点之间必经的点就是圆方树上两点之间的圆点 所以只需建出圆方树 每次询问建出虚树,统计一下虚树边上有多少圆点即可 还要讨论一下经不经过根\(1\)的情 ...

  9. 洛谷P4606 [SDOI2018]战略游戏 [广义圆方树]

    传送门 思路 先考虑两点如何使他们不连通. 显然路径上所有的割点都满足条件. 多个点呢?也是这样的. 于是可以想到圆方树.一个点集的答案就是它的虚树里圆点个数减去点集大小. 可以把点按dfs序排序,然 ...

随机推荐

  1. 引发类型为“System.OutOfMemoryException”的异常

    在运维工作中,经常能接到客户的反馈这个:引发类型为“System.OutOfMemoryException”的异常.客户反馈物理内存都还有富余,怎么报内存不足的错误呢! 什么时候会引发System.O ...

  2. 多校 HDU 6397 Character Encoding (容斥)

    题意:在0~n-1个数里选m个数和为k,数字可以重复选: 如果是在m个xi>0的情况下就相当于是将k个球分割成m块,那么很明显就是隔板法插空,不能为0的条件限制下一共k-1个位置可以选择插入隔板 ...

  3. python的新特性

    http://www.jb51.net/article/67699.htm Python中用format函数格式化字符串的用法:http://www.jb51.net/article/63672.ht ...

  4. mysql基准测试工具tpcc-mysql安装、使用、结果解读

    TPCC是专门针对联机交易处理系统(OLTP系统)的规范,一般情况下我们也把这类系统称为业务处理系统,tpcc-mysql是percona基于TPC-C(下面简写成TPCC)衍生出来的产品,专用于My ...

  5. 经典面试题:js继承方式上

    js不是传统的面向对象语言,那么他是怎么实现继承的呢?由于js是基于原型链实现的面向对象,所以js主要通过原型链查找来实现继承,主要有两大类实现方式,分为基于构造函数的继承,以及非构造函数的继承. 由 ...

  6. 使用Jsoup解析出html中的img元素

    jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址.HTML文本内容.它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据. 博客项目 ...

  7. Python 安装 pytesser 处理验证码出现的问题

    今天这个问题困扰了我好久,开始直接用 pip install pytesseract 安装了 pytesseract 然后出现了如下错误 Traceback (most recent call las ...

  8. 接口测试工具--Poster与Postman的简单实用

    HTTP/SOAP协议接口的功能测试: 1.浏览器URL(GET请求) http://127.0.0.1:8000/login/?username=zhangsan&password=1234 ...

  9. 20155309 《Java程序设计》实验三(Java面向对象程序设计)实验报告

    一.实验内容及步骤 (一)编码标准 在IDEA中使用工具(Code->Reformate Code)把代码重新格式化. (二)在码云上把自己的学习搭档加入自己的项目中,确认搭档的项目加入自己后, ...

  10. Java模拟按键

    JDK自带了Robot类,此类用于为测试自动化.自运行演示程序和其他需要控制鼠标和键盘的应用程序生成本机系统输入事件.Robot 的主要目的是便于 Java 平台实现自动测试. 详情可查看jdk1.6 ...