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序排序,然 ...
随机推荐
- c# 通过Windows服务启动外部程序
1. 新建一个Windows服务应用程序 创建项目——>Visual C# 左侧的"+"——>Windows ——>Windows 服务(右侧模板)——>输 ...
- Python之内建函数Map,Filter和Reduce
Python进阶 map,filter, reduce是python常用的built-in function. 且常与lambda表达式一起用. 其中: map 形式:map(function_to_ ...
- DenseNet笔记
一.DenseNet的优点 减轻梯度消失问题 加强特征的传递 充分利用特征 减少了参数量 二.网络结构公式 对于每一个DenseBlock中的每一个层, [x0,x1,…,xl-1]表示将0到l-1层 ...
- springboot配置fastjson后端往前端传输格式化
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.Spri ...
- Linux下实现ping功能
实现ping功能,就肯定要用到ping命令,那么在Linux下ping命令为: ping [-dfnqrRv][-c<完成次数>][-i<间隔秒数>][-I<网络界面&g ...
- irport报表,把数字金额转换成大写人民币金额
1.编写oracle函数 CREATE OR REPLACE Function MoneyToChinese(Money In Number) Return Varchar2 Is strYuan ) ...
- MyBatis框架的基本使用
MyBatis框架简介 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名 ...
- epoll对poll(select)的改进
select的几大缺点: 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大: 每次调用select,内核需要遍历传递进来的所有fd(判断检测文件是否可用).有 ...
- vim 中替换命令
vi/vim 中可以使用 :s 命令来替换字符串.以前只会使用一种格式来全文替换,今天发现该命令有很多种写法(vi 真是强大啊,还有很多需要学习),记录几种在此,方便以后查询. :s/vivian/s ...
- sqlserver字符串合并(merge)方法汇总
--方法1--使用游标法进行字符串合并处理的示例.--处理的数据CREATE TABLE tb(col1 varchar(10),col2 int)INSERT tb SELECT 'a',1UNIO ...