[XSY] 分割(dfs树)

分割
题目相当于问 删掉两个点后 图是否仍然连通
割点问题,考虑用dfs树解决
设删去点u,v(dfn[v]<dfn[u])
把 u, v 删去之后整棵树大概断成了几个部分:
• v 上面到根的部分,以及上面挂着的那些东西,记作 highhighhigh
• u 到 v 之间的那一段,以及上面挂着的那些东西,记作 midmidmid
• u ,v的子树们,记作 lowulow_ulowulowvlow_vlowv
在这里插入图片描述
要保证删去u,v后图连通,则lowulow_ulowumidmidmidlowvlow_vlowv必须想办法和highhighhigh连通

lowvlow_vlowv:每颗子树有非树边连接highhighhigh
lowulow_ulowu:每颗子树 有非树边连接highhighhigh 或 有非树边连接midmidmidmidmidmid有非树边连接highhighhigh
midmidmid:有非树边连接highhighhigh有非树边连接lowulow_ulowu的其中一颗子树,同时这颗子树有非树边连接highhighhigh

当然,fa[u]==vfa[u]==vfa[u]==v的情况略有不同,且v==1v==1v==1时要特判


上面的思路除了 加粗字体的情况 没考虑到,其它都想到了
以下是想不出来的实现:


对于 子树内有非树边连接highhighhigh 的条件:
预处理出 low[u] 表示 以u为根的子树通过非树边最高能连到的位置

对于 midmidmid有非树边连接highhighhigh 的条件:
预处理出 g[u][k] 表示 u到其2k2^k2k次祖先 的这一段以及上面挂着的东西中,不算 u,通过非树边最高能到的位置(树上倍增)
(注意:g[u][0]!=low[fa[u]],详见代码)

对于 lowulow_ulowu中有非树边连接midmidmid 的条件:
考虑转化一下条件,
原条件为 对于lowulow_ulowu的任意一颗子树,若在[1,dfn[v]-1]中没有通过非树边能连到的位置,那么在[dfn[v]+1,dfn[u]-1]中至少有一个通过非树边能连到的位置
我们将其转化为 lowulow_ulowu中有一颗子树在[1,dfn[v]-1]和[dfn[v]+1,dfn[u]-1]中均没有通过非树边能连到的位置,那么边(u,v)不能删
在这里插入图片描述
如图,w为u的其中一颗子树,标紫的点是w通过非树边能连到的位置中在u上方的部分,可以发现,只有v在low[w]及其往上的部分时,[1,dfn[v]-1]中才会没有w通过非树边能连到的位置,这时若[dfn[v]+1,dfn[u]-1]中没有其它w通过非树边能连到的位置,即dfn[w通过非树边第二高能连到的位置]>=dfn[u],则(u,v)不能删

预处理出 slow[u] 表示 以u为根的子树通过非树边第二高能连到的位置即可
(同学教的,妙啊!)

对于 midmidmid有非树边连接lowulow_ulowu的其中一颗子树,同时这颗子树有非树边连接highhighhigh 的条件:
还是考虑转化条件,
原条件为 lowulow_ulowu中有一颗子树,在[1,dfn[v]-1]和[dfn[v]+1,dfn[u]-1]中均有其通过非树边能连到的位置
转化为 对于lowulow_ulowu的其中一颗子树,记l,rl,rl,r为这棵子树通过非树边能连到的位置中在u上方部分的最高点和最低点,若 lll<=dfn[v]-1 且 rrr>=dfn[v]+1,即lll+1<=dfn[v]<=rrr-1,那么(u,v)边的midmidmid部分一定能通过连接这颗子树连到highhighhigh

具体地,lll即为low[son[u]],
对每个点u维护一个优先队列,记录以u为根的子树通过非树边能连到的位置,pop出 son[u] 的优先队列中 dfn值>=dfn[u] 的位置即可找到rrr(优先队列合并)


对于最后两个条件,我一开始想的是暴力维护每个点u即它的子树通过非树边能连到的所有位置(以dfn序为下标建线段树,维护区间内能连接到的位置的个数(类似权值线段树的感觉)),然后合并线段树
虽然后来了解到合并线段树的时间复杂度是O(nlogn)O(nlogn)O(nlogn),所以整道题的复杂度也就O(nlog2n)O(nlog^2n)O(nlog2n),即理论复杂度也是对的,但是常数过大,大概率会T

但是syh大佬通过把 判断对于确定的u,v,(u,v)是否可删 转化为 对于确定的u,寻找什么样的v满足(u,v) 可删/不可删,让这题有了简单许多的做法 OrzOrzOrz


Code:

#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int N=3e5+5;
struct data{int v,nxt;
}edge[N<<1];
vector<int> vex[N],vid[N];
int n,m,cnt,head[N],ind,dfn[N],sz[N],son[N],fa[N][21];
int low[N],slow[N],g[N][21];
int st[N<<2];
int fl[N],hk[N];
//fl[u]=删掉u后,有几个u的子节点会被与连通图断开 
//hk[v]=删掉fa[v][0]后,v会与连通图断开 
map<int,int> mp[N];
//mp[a][b]=1表示为保持图连通,若删了a,则b不能被删 
bool fla[N],flagg[N];
int rt[N];
priority_queue<int> q[N];
queue<int> que;
void add(int u,int v){edge[++cnt].v=v;edge[cnt].nxt=head[u];head[u]=cnt;
}
void merge(int a,int b){int p[11];p[1]=low[a];p[2]=slow[a];p[3]=low[b];p[4]=slow[b];sort(p+1,p+5);low[a]=p[1];slow[a]=n+1;for(int i=2;i<=4;i++){if(p[i]!=p[i-1]){slow[a]=p[i];break;}}
}
inline void dfs(int u){ind++;dfn[u]=ind;for(int i=head[u];i;i=edge[i].nxt){if(!dfn[edge[i].v]){fa[edge[i].v][0]=u;dfs(edge[i].v);}    }
}
void dfs_tree(int u){//判low直接与high连通+low通过mid与high连通 sz[u]=1;low[u]=dfn[u];slow[u]=n+1;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(v==fa[u][0]) continue;if(fa[v][0]==u){son[u]++;dfs_tree(v);merge(u,v);sz[u]=sz[u]+sz[v];if(low[v]>=dfn[u]){fl[u]++;hk[v]++;}else if(slow[v]>=dfn[u]) mp[u][low[v]]=1;}else{if(dfn[v]==low[u]) continue;if(low[u]>dfn[v]){slow[u]=low[u];low[u]=dfn[v];}else if(slow[u]>dfn[v]) slow[u]=dfn[v];}}
}
//此时的线段树用于统计low的最小值 
inline void update(int u,int l,int r,int x,int v){if(l>x||r<x)return;if(l==r){st[u]=v;return;}int mid=(l+r)/2;update(u<<1,l,mid,x,v);update(u<<1|1,mid+1,r,x,v);st[u]=min(st[u<<1],st[u<<1|1]);
}
inline int query(int u,int l,int r,int ql,int qr){if(l>qr||r<ql)return n+1;if(ql<=l&&r<=qr)return st[u];int mid=(l+r)/2;int res1=query(u<<1,l,mid,ql,qr);int res2=query(u<<1|1,mid+1,r,ql,qr);return min(res1,res2);
}
//此时的线段树用于维护区间是否可选 
inline void modify(int u,int l,int r,int ql,int qr){if(!flagg[u]){que.push(u);flagg[u]=1;}if(l>qr||r<ql)return;if(ql<=l&&r<=qr){st[u]=1;return;}int mid=(l+r)/2;modify(u<<1,l,mid,ql,qr);modify(u<<1|1,mid+1,r,ql,qr);st[u]=st[u<<1]&st[u<<1|1];
}
inline bool ask(int u,int l,int r,int x){if(l>x||r<x) return 0;if(st[u]) return st[u];if(l==r) return st[u];int mid=(l+r)/2;return ask(u<<1,l,mid,x)|ask(u<<1|1,mid+1,r,x);
}
inline void get_g(int u){//判mid不通过low直接与high连通  for(int i=1;i<=20;i++){fa[u][i]=fa[fa[u][i-1]][i-1];g[u][i]=min(g[u][i-1],g[fa[u][i-1]][i-1]);}int sum=0,tot=0,s=n+1;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(v==fa[u][0]) continue;if(fa[v][0]==u) sum++;else s=min(s,dfn[v]);}for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(fa[v][0]==u){tot++;update(1,1,sum,tot,low[v]);}}tot=0;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(fa[v][0]==u){tot++;g[v][0]=min(min(query(1,1,sum,1,tot-1),query(1,1,sum,tot+1,sum)),s);}}for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(fa[v][0]==u) get_g(v);}
}
int solve(int u,int v){int s=n+1;for(int i=20;i>=0;i--){if(dfn[fa[v][i]]>dfn[u]){s=min(s,g[v][i]);v=fa[v][i];}}return s;
}
int mergeq(int a,int b){if(q[a].size()<q[b].size()) swap(a,b);while(!q[b].empty()){q[a].push(q[b].top());q[b].pop();}return a;
}
inline void getans(int u){//判mid通过low与high连通 for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(fa[v][0]==u) getans(v);}	rt[u]=u;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(v==fa[u][0])continue;if(fa[v][0]==u){int l=low[v],r=0;while(!q[rt[v]].empty()){if(q[rt[v]].top()>=dfn[u]) q[rt[v]].pop();else{r=q[rt[v]].top();break;}}modify(1,1,n,l+1,r-1);//对于非树边(u,y)(dfn[y]<dfn[u]),若dfn[y]在[l+1,r-1]的区间内,则删去此边后(u,y)边的mid部分仍与high连通 rt[u]=mergeq(rt[v],rt[u]);}else{q[rt[u]].push(dfn[v]);}}for(int i=0;i<vex[u].size();i++){int x=u;int y=vex[u][i];int z=vid[u][i];if(dfn[y]>dfn[x])continue;if(x==1||y==1)continue;if(y==fa[x][0])continue;if(!ask(1,1,n,dfn[y]))fla[z]=1;}while(!que.empty()){flagg[que.front()]=0;st[que.front()]=0;que.pop();}//恢复 
}
char check(int id,int a,int b){if(dfn[a]>dfn[b]) swap(a,b);if(a==1){if(fa[b][0]==a){if(son[a]>2) return '1';if(son[a]>1&&sz[b]>1) return '1';if(son[b]>1) return '1';return '0';}if(son[a]>1) return '1';if(mp[b][dfn[a]]==0&&fl[b]==0) return '0';return '1';}if(fa[b][0]==a){if(sz[b]==1&&hk[b]==1){if(fl[a]<=1&&fl[b]==0&&mp[b][dfn[a]]==0) return '0';}else{if(fl[a]==0&&fl[b]==0&&mp[b][dfn[a]]==0) return '0';}return '1';}if(fl[a]||fl[b]||mp[b][dfn[a]]) return '1';int s=solve(a,b);if(s>=dfn[a]&&fla[id]) return '1';return '0';
}
int main(){scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);add(x,y);add(y,x);vex[x].push_back(y);vex[y].push_back(x);vid[x].push_back(i);vid[y].push_back(i);}dfs(1);dfs_tree(1);get_g(1);for(int i=1;i<=n*4;i++) st[i]=0;getans(1);for(int i=1;i<=m;i++)putchar(check(i,edge[i*2-1].v,edge[i*2].v));
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/320221.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P4068-[SDOI2016]数字配对【二分,费用流】

正题 题目链接:https://www.luogu.com.cn/problem/P4068 题目大意 nnn种数字&#xff0c;第iii个是aia_iai​&#xff0c;有bib_ibi​个&#xff0c;价值为ci∗cjc_i*c_jci​∗cj​ 如果一个数字axa_xax​和aya_yay​配对要求axay\frac{a_x}{a_y}ay​ax​​是一个质数且产生c…

三分法讲解

二分用到的挺多&#xff0c;三分用的少&#xff0c;但也不能忘。。。 二分我们常常用于一个具有单调性的情况中求解某值 而三分就像是求一个凸性或凹形函数时&#xff0c;来求那个凹凸点 一开始L0&#xff0c;Rinf&#xff0c;然后也是不断缩小L与R的范围&#xff0c;逼近最值…

秀姿势(jzoj 3464)

秀姿势 jzoj 3464 题目大意 有n个数&#xff0c;每个数都有一个分组&#xff0c;现在问你最多去掉k个分组后&#xff0c;做多有多少个数是连续的同组的 输入样例 9 1 2 7 3 7 7 3 7 5 7输出样例 4样例解释 总共有9个学生&#xff0c;最多只能刷一次学生。 若不刷&#x…

使用C#读写结构化的二进制文件

最近工作上遇到一个问题&#xff0c;就是有将近200万个CSV文件&#xff0c;每个CSV文件包含了成千上万条实验数据&#xff0c;CSV以一个不连续的整数值作为文件名&#xff0c;比如&#xff1a;1.CSV、2.CSV、3.CSV、5.CSV等等。另外又有200万个XML文件&#xff0c;每个XML文件的…

[XSY] 相似(DP套DP)

相似 在看这道题前&#xff0c;有必要先看一下DP套DP的入门题[uoj3864]Hero meet devil&#xff0c;附上两篇写得不错的题解&#xff1a; https://blog.csdn.net/Ike940067893/article/details/87863041 https://www.cnblogs.com/RabbitHu/p/BZOJ3864.html 可以发现&#xff…

P3295-[SCOI2016]萌萌哒【ST表,并查集】

正题 题目链接:https://www.luogu.com.cn/problem/P3295 题目大意 一个nnn位的数字&#xff0c;mmm个条件给出两个完全相同的区间&#xff0c;求可能的数字数量。 解题思路 其实就是区间中的每个数字分别连边&#xff0c;但是这样显然会TTT。考虑通过消耗查询的复杂度来平衡…

牛客IOI周赛16-普及组

比赛链接 文章目录求导题目描述题解&#xff1a;猜数题意&#xff1a;题解&#xff1a;方法一 贪心方法二 暴力答题卡题意&#xff1a;题解&#xff1a;代码&#xff1a;求导 链接&#xff1a; 时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C …

【归并排序】休息(jzoj 3462)

休息 jzoj 3462 题目大意 给你一个序列&#xff0c;你每一回合把它划分成尽可能少的单调递减的序列&#xff08;第一次划分到的序列长度都是偶数&#xff09;&#xff0c;然后把每个序列翻转&#xff0c;问你把它变成单调递增的序列要翻转多少次 输入样例 6 5 3 2 1 6 4输…

Pipelines - .NET中的新IO API指引(二)

原文&#xff1a;Pipelines - a guided tour of the new IO API in .NET, part 2作者&#xff1a;marcgravell在上一章&#xff0c;我们讨论了以往的StreamAPI中存在的一些问题&#xff0c;并且介绍了Pipe,PipeWriter,PipeReader 等API&#xff0c;研究如何写出一个Pipe 并且从…

[XSY] 线图(树形DP、分类讨论)

线图 如图&#xff0c;每个L(L(T))上的点对应T上的一条三点链 在连接L(L(T))上两点&#xff0c;当且仅当两点代表的三点链在T上有共边&#xff0c;且边权为 共边边权*2非共边1边权非共边2边权 在L(L(T))上从点u走到点v&#xff0c;等价于u代表的三点链在T上删掉自己的一条边&…

Bzoj3309-DZY Loves Math【莫比乌斯反演,线性筛】

正题 bzoj没了&#xff0c;在darkbzoj交吧 题目链接:https://darkbzoj.tk/problem/3309 题目大意 定义f(x)f(x)f(x)表示xxx所有质因数中最大的指数幂。 求∑i1n∑j1mf(gcd(i,j))\sum_{i1}^n\sum_{j1}^mf(\ gcd(i,j)\ )i1∑n​j1∑m​f( gcd(i,j) ) 解题思路 很显然要用莫反…

牛客网【每日一题】4月29日题目精讲 Symmetric Matrix

链接&#xff1a; 时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 524288K&#xff0c;其他语言1048576K 64bit IO Format: %lld题目描述 输入描述: The input consists of several test cases and is terminated by end-of-file. Each test c…

邻接矩阵和邻接表的使用

邻接矩阵和邻接表的使用 邻接矩阵 为了遍历一个图&#xff0c;我们使用了邻接矩阵&#xff0c;及用ai,ja_{i,j}ai,j​表示由a到b的边权 注&#xff1a;若这两个点不相连或ijijij&#xff0c;那么这个值就会设定为一个非正常的值&#xff0c;以便遍历时特判不走这条边 使用&am…

YbtOJ#20239-[冲刺NOIP2020模拟赛Day10]连边方案【状压dp】

正题 题目链接:https://www.ybtoj.com.cn/contest/68/problem/3 题目大意 求有多少个nnn个点mmm条边的无向图满足 有连边的点之间编号差不超过kkk所有点的度数都为偶数 解题思路 因为kkk很小&#xff0c;所以我们考虑状压一个点前kkk个点的奇偶状态。设fi,j,s,0/1f_{i,j,s,…

有上下界网络流问题汇总

无源汇有上下界可行流 法一&#xff08;据说适合点少边多的图&#xff09;&#xff1a; 建图方法 首先建立附加源点ss和附加汇点tt对于原图中的边x->y&#xff0c;若限制为[b,c]&#xff0c;那么连边x->y&#xff0c;流量为c-b对于原图中的某一个点i&#xff0c;记d(i…

一个迄今为止最快的并发键值存储库FASTER诞生

FASTER在过去十年中&#xff0c;云中的数据密集型应用程序和服务有了巨大的增长。数据在各种边设施&#xff08;例如&#xff0c;设备&#xff0c;浏览器和服务器&#xff09;上创建&#xff0c;并由云应用程序处理用来获得数据价值或做出决策。应用程序和服务可以处理收集的数…

【斜率优化】仓库建设(luogu 2120)

仓库建设 luogu 2120 题目大意 有一个斜坡&#xff0c;上面有n个工厂&#xff08;山顶是1&#xff0c;山脚是nnn&#xff0c;工厂都是漏填&#xff09;&#xff0c;上面有pip_ipi​个货物&#xff0c;和工厂1的距离为x1x_1x1​ 现在有一场大雨&#xff0c;你可以在某些工厂处…

牛客网【每日一题】4月30日题目精讲 换个角度思考

链接&#xff1a; 文章目录题目描述题解&#xff1a;主席树做法&#xff1a;代码&#xff1a;树状数组&#xff1a;更扯淡的方法&#xff01;&#xff01;&#xff01;时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 262144K&#xff0c;其他语言…

三元环计数四元环计数

三元环计数 问题 给出一张n个点m条边的无向图&#xff0c;问图中有多少个三元组{ u , v , w } &#xff0c;满足图中存在 { (u,v) , (v,w) , (w,u) } 三条边。 求解 Step1 定向 将所有点按 度数 从小到大排序&#xff0c;如果度数相同按 点编号 从小到大排序&#xff0c;u…

YbtOJ#20240-[冲刺NOIP2020模拟赛Day10]弱者对决【笛卡尔树,区间dp】

正题 题目链接:https://www.ybtoj.com.cn/contest/68/problem/4 题目大意 mmm个三元组(ai,bi,ci)(a_i,b_i,c_i)(ai​,bi​,ci​)&#xff0c;如果ci≥min{xj}(ai≤j≤bi)c_i\geq min\{x_j\}(a_i\leq j\leq b_i)ci​≥min{xj​}(ai​≤j≤bi​)那么可以获得min{xj}min\{x_j\}mi…