首页 > 其他分享 >P7712 [Ynoi2077] hlcpq 题解

P7712 [Ynoi2077] hlcpq 题解

时间:2023-03-09 21:44:27浏览次数:54  
标签:遍历 nl int 题解 mid P7712 hlcpq low 节点

虚式优化建图题。

首先有一个很显然的暴力,对于两条相交的线段连一条边,然后跑割点。

这个暴力的问题在于边与点的时间复杂度相差过大,无论是空间还是时间都无法承受,所以可以想到去优化建图。

首先我们假设点与边的复杂度相同,那么我们空间是承受的下的,现在想要时间承受下,由于是二维平面图,很容易想到去用扫描线。用垂直的直线去扫,扫到左端点连边,扫到右端点后不再连边,可以用队列维护。

基于这个思路,我们在这道题也用扫描线,但是队列里的元素过多,是无法承受的,乍一看队列里的元素是没有规律的,但是对于一条水平线,它进出时间是连续的,所以根据它的进出时间来判断,左端点入队,右端点出队,用线段树维护,由于每个版本都是需要用到的,显然使用主席树即可。

那么我们处理出了每个垂直线段与水平线段的相交情况,那么再横着扫一次,就处理出了每个水平线段与垂直线段的相交情况。

现在我们把所有的相交情况处理到了一棵主席树上,我们要拿它去跑割点,问题在于怎么去跑。

我们知道我们在跑割点时,维护了 \(dfn,low\) 两个值,而 \(dfn\) 是不变的,所以不需要管它,在转移 \(low\) 时,我们要判断这个点是否被遍历过,记为 \(vis\) 数组。

所以现在我们要动态维护 \(low,vis\),这东西好像直接在遍历的时候改一下值就行了……

处理好动态维护,下一个的就是遍历点了,如何得到这个点连向的下一个未被遍历的点呢。

我们首先先预处理出每个区间未使用过的点,初始时就对于每一个顶层节点 \(+1\) 然后往上 \(pushup\)。当遍历到那个节点时,将其所在的节点 \(-1\),往上 \(pushup\) 即可。

最后一步即是求连接的点中最小的 \(dfn\) 值,虽然对于由它转移出去的点是由 \(low\) 值转移的,但众所周知 \(low\le dfn\) 所以不会影响,那么这个好弄,在第一遍历到这个节点时在对应节点修改,最后维护区间最小值即可。

注意处理根节点的情况,根节点是遍历节点数大于二才为割点。

时间复杂度:\(O(n\log(n))\)

点击查看代码
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int N=2e5+5;
int n,L[N],R[N],m,cnt,p[N],ans[N],dfn[N],low[N],rt[N],cnp;
vector<int>a[N],b[N];
namespace tree
{
	struct node
	{
		int ls,rs,minn,sum;
	}f[40*N];
	inline void pushup(int x)
	{
		//cout<<x<<" "<<f[x].ls<<" "<<f[x].rs<<" "<<f[f[x].ls].minn<<" "<<f[f[x].rs].minn<<endl;
		f[x].sum=f[f[x].ls].sum+f[f[x].rs].sum;
		f[x].minn=min(f[f[x].ls].minn,f[f[x].rs].minn);
	}
	void update(int &x,int y,int l,int r,int nl,int k)
	{
		if(!x)x=++cnt;
		f[x]=f[y];
		
		if(l==r)
		{
			f[x].sum+=k;
			if(k==1)p[nl]=x;
			return;
		}
		int mid=(l+r)>>1;
		if(mid>=nl)update(f[x].ls=0,f[y].ls,l,mid,nl,k);
		else update(f[x].rs=0,f[y].rs,mid+1,r,nl,k);
		pushup(x);
	}
	int search(int x,int l,int r,int nl,int nr)
	{
		//cout<<x<<" "<<l<<" "<<r<<" "<<nl<<" "<<nr<<" "<<f[x].minn<<endl;//1666
		if(!x||(l>=nl&&r<=nr))return f[x].minn;
		int mid=(l+r)>>1,ans=1e9;
		if(mid>=nl)ans=min(ans,search(f[x].ls,l,mid,nl,nr));
		if(mid<nr)ans=min(ans,search(f[x].rs,mid+1,r,nl,nr));
		return ans;
	}
	int getnode(int x,int l,int r,int nl,int nr)
	{
		if(!f[x].sum)return 0;
		if(l==r)
		{
			//cout<<x<<endl;
			f[x].sum=0;
			f[x].minn=++cnp;
			return l;
		}
		int mid=(l+r)>>1;
		int num=0;
		if(mid>=nl)num=getnode(f[x].ls,l,mid,nl,nr);
		if(num)
		{
			pushup(x);
			return num;
		}
		if(mid<nr)
		{
			int num=getnode(f[x].rs,mid+1,r,nl,nr);
			pushup(x);
			return num;
		}
		pushup(x);
		return 0;
	}
}
using namespace tree;
void Tarjan(int x,bool ss)
{
	int son=0;
	dfn[x]=low[x]=cnp;
	int i=getnode(rt[x],1,m,L[x],R[x]);
	//cout<<endl;
	for(;i;i=getnode(rt[x],1,m,L[x],R[x]))
	{
		//cout<<endl;
		son++;
		Tarjan(i,1);
		low[x]=min(low[x],low[i]);
		//cout<<x<<" "<<i<<" "<<L[i]<<" "<<R[i]<<" "<<dfn[x]<<" "<<low[i]<<endl;
		if(dfn[x]==low[i])ans[x]=1; 
	}
	low[x]=min(low[x],search(rt[x],1,m,L[x],R[x]));
	if(!ss)ans[x]=son>1;
}
int main()
{
//	freopen("segment4.in","r",stdin);
//	freopen("data.out","w",stdout);
	scanf("%d",&n);
	m=2*n;
	for(int i=1;i<=n;i++)scanf("%d%d",&L[i],&R[i]),L[i]+=n,R[i]+=n;
	for(int i=1;i<=n;i++)scanf("%d%d",&L[i+n],&R[i+n]);
	for(int i=1;i<=m;i++)a[L[i]].push_back(i),b[R[i]+1].push_back(i);
	f[0].minn=1e9;
	for(int i=1;i<=m;i++)
	{
		rt[i]=++cnt;
		f[rt[i]]=f[rt[i-1]];
		int len=a[i].size();
		for(int j=0;j<len;j++)update(rt[i],rt[i],1,m,a[i][j],1);
		len=b[i].size();
		for(int j=0;j<len;j++)update(rt[i],rt[i],1,m,b[i][j],-1);
	}
//	cout<<cnt<<endl;
	//cout<<f[82].ls<<" "<<f[82].rs<<endl;
	for(int i=1;i<=m;i++)if(!dfn[i])f[p[i]].sum=0,f[p[i]].minn=++cnp,Tarjan(i,0);
	//for(int i=1;i<=m;i++)cout<<i<<" "<<dfn[i]<<" "<<low[i]<<endl;
	for(int i=1;i<=n;i++)printf("%d",ans[i]);
	printf("\n");
	for(int i=1;i<=n;i++)printf("%d",ans[i+n]);
	printf("\n");
	return 0;
}

标签:遍历,nl,int,题解,mid,P7712,hlcpq,low,节点
From: https://www.cnblogs.com/gmtfff/p/p7712.html

相关文章

  • CF1713F 题解
    题意传送门给出一个从\(1\)到\(n\)的数组\(a\),有一个从\(0\)开始标号的大小为\((n+1)\times(n+1)\)的矩阵\(b\),通过以下方式生成:对于\(0\lei\len\),\(b_{i......
  • 江南信息学2023第三周练习20230310 题解
    比赛链接1001:三个数的最大值条件判断,如判断a最大就是a>=b&&a>=c,以此类推1002:星期几取余,n%7结果是0则是周一,是1则周二,以此类推1003:奇偶分家设两个求和变量sum1,sum2......
  • ABC292F题解
    首先先钦定\(a\leb\),否则交换一下就行。方法1:二分答案。容易发现,答案至少为\(a\),并且用左下角为一个顶点一定不会更劣,并且另外两个点一定都在线段上(否则可以调整)。我们......
  • CF207C3 Game with Two Trees 题解
    脑子不够,科技来凑。不过好像也没有用多么高级的科技……首先这个题目很坏,它让你翻转\(S_{t_2}\)。即从\(t_2\)某个节点往下走到另一个节点的路径所表示的字符串。这个......
  • Python自动化登录验证码问题解决
     1.测试环境中通常解决验证码问题的方法 在测试环境中我们通常通过各种手段来逃避或者获得验证,而这些手段主要是要求开发者在开发的时候留有一定的后门。下面简述几种......
  • 【题解】ARC157 A-D
    因为有的题代码没写出来,所以代码就先咕咕咕了。A.XXYYX题目分析:可以发现每一个XY必然伴随着出现一次YX,当然可能会有一个XY没有伴随的YX的。而且若必须存在XX......
  • 【题解】[Ynoi2015] 我回来了
    题目分析:所谓的期望乘以\(R-L+1\)其实就是求亵渎的触发次数,因为我们能选择的伤害只有\(R-L+1\)种。有一个很显然的转化,就是对于伤害\(d\),我们以随从的血量......
  • DP练习1题解
    这是2023.3.7DP题单十个题的题解。T1ColoredSubgraphs(CF1796E)简要题意:给定一棵树,你要对树进行链剖分,必须剖成上下竖直的链,求剖后最短链的长度最大值。最小值最大......
  • 【题解】[Ynoi2013] 大学
    题目分析:考虑对于一次修改至少会让\(x\)变成\(\frac{x}{2}\)所以对于每一个数最多被操作\(\log{n}\)次,那么直接暴力操作就好了。所以其实关键问题是每次怎么找到哪......
  • QOJ5256 [CERC2022] H. Insertions 题解
    题面题意:给定字符串\(S,T,P\),求将\(T\)插入进\(S\)之后\(P\)最多的出现次数。输出:最多的出现次数;达到这个最多出现次数的插入位置数量;达到这个最多出现次数......