[BZOJ1018]SHOI2008堵塞的交通|线段树

本文探讨了一种使用线段树维护区间内联通性的创新算法,不仅适用于传统的区间信息维护,还能解决复杂的联通性问题。通过详细解释实现思路与关键步骤,文章展示了如何将线段树应用于解决实际问题,包括合并节点信息、获取答案等操作。通过实例演示,读者可以深入了解这一算法的实际应用与优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     好神的线段树题,以前只会维护区间什么数值信息的,竟然还可以维护联通性,好题啊,涨姿势了。。

    由于只有两行嘛,要保证线段树节点有可加性,我们维护六个信息,分别是右上到右下,右上到左上,右上到左下,右下到左上,右下到左下,左上到左下的联通性,合并的时候自己YY一下,还是很好想的。一点要注意的,父节点的左上到左下不能简单的直接把左儿子的值赋上去,还有可能是左走到右再走回来,右上右下的同理。。然后就是获取答案的时候,不一定就是在[L,R]这个区间里走,有可能会出现像R向右绕一个弯再走过去这样的情况,所以要把[1,L][L,R][R,n]三个区间的联通性都获取。。细节还是很多的。。

#include<cstdio>
#include<iostream>
#include<memory.h>
#define lc x*2
#define rc x*2+1
#define N 400405
using namespace std;
int n,x1,y1,x2,y2,qd,ans,ansl,ansr;
bool l12[N],r12[N],lr1[N],lr2[N],l1r2[N],l2r1[N],a[N][2][2];//a数组0向下1向右 
char s[10];
void build(int x,int l,int r)
{
	if (l==r)
	{
		lr1[x]=lr2[x]=true;
		return;
	}
	build(lc,l,(l+r)>>1);build(rc,(l+r)/2+1,r);
}
void update(int x,int mid,int lcc,int rcc)
{
	l12[x]=l12[lcc]||(lr1[lcc]&&a[mid][0][1]&&l12[rcc]&&a[mid][1][1]&&lr2[lcc]);
	r12[x]=r12[rcc]||(lr1[rcc]&&a[mid][0][1]&&r12[lcc]&&a[mid][1][1]&&lr2[rcc]);
	lr1[x]=(lr1[lcc]&&a[mid][0][1]&&lr1[rcc])||(l1r2[lcc]&&a[mid][1][1]&&l2r1[rcc]);
	lr2[x]=(lr2[lcc]&&a[mid][1][1]&&lr2[rcc])||(l2r1[lcc]&&a[mid][0][1]&&l1r2[rcc]);
	l1r2[x]=(lr1[lcc]&&a[mid][0][1]&&l1r2[rcc])||(l1r2[lcc]&&a[mid][1][1]&&lr2[rcc]);
	l2r1[x]=(lr2[lcc]&&a[mid][1][1]&&l2r1[rcc])||(l2r1[lcc]&&a[mid][0][1]&&lr1[rcc]);
}
void change(int x,int l,int r,int x1,int y1,int x2,int y2,bool k)
{
	int mid=(l+r)/2;
	if (y1==y2) 
	{
		if (l==r) 
		{
			a[y1][0][0]=k;
			l12[x]=r12[x]=l1r2[x]=l2r1[x]=k;
			return;
		}
		if (y1<=mid) change(lc,l,mid,x1,y1,x2,y2,k);else change(rc,mid+1,r,x1,y1,x2,y2,k);
		update(x,mid,lc,rc);
	}
	else
	{
		a[y1][x1][1]=k;
		if (mid==y1&&mid+1==y2) update(x,mid,lc,rc);
		else
		{
			if (mid>=y2) change(lc,l,mid,x1,y1,x2,y2,k);else change(rc,mid+1,r,x1,y1,x2,y2,k);
			update(x,mid,lc,rc);
		}
	}
}
int query(int x,int l,int r,int y1,int y2)
{
	if (y1<=l&&y2>=r) return x;
	int mid=(l+r)>>1;
	if (y2<=mid) return query(lc,l,mid,y1,y2);
	else if (y1>mid) return query(rc,mid+1,r,y1,y2);
	else
	{
		int ans=++qd,lcc=query(lc,l,mid,y1,mid),rcc=query(rc,mid+1,r,mid+1,y2);
		update(ans,mid,lcc,rcc);
		return ans;
	}
}
int main()
{
	freopen("1018.in","r",stdin);
//	freopen("1018.out","w",stdout);
	scanf("%d",&n);
	memset(a,0,sizeof(a));
	memset(l12,0,sizeof(l12));memset(r12,0,sizeof(r12));
	memset(lr1,0,sizeof(lr1));memset(lr2,0,sizeof(lr2));
	memset(l2r1,0,sizeof(l2r1));memset(l1r2,0,sizeof(l1r2));
	build(1,1,n);
	int t=1;
	while (t++)
	{
		scanf("%s",&s);
		if (s[0]=='E') return 0;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if (y1>y2) swap(y1,y2),swap(x1,x2);	
		x1--;x2--;
		if (s[0]=='O') change(1,1,n,x1,y1,x2,y2,true);
		else if (s[0]=='C') change(1,1,n,x1,y1,x2,y2,false);
		else 
		{
			qd=400000;
			ans=query(1,1,n,y1,y2);ansl=query(1,1,n,1,y1);ansr=query(1,1,n,y2,n);
			if ((x1==0&&x2==0&&(lr1[ans]||(r12[ansl]&&l2r1[ans])||(l12[ansr]&&l1r2[ans])||(r12[ansl]&&l12[ansr]&&lr2[ans])))||(x1==1&&x2==1&&(lr2[ans]||(r12[ansl]&&l1r2[ans])||(l12[ansr]&&l2r1[ans])||(r12[ansl]&&l12[ansr]&&lr1[ans])))||(x1==0&&x2==1&&(l1r2[ans]||(r12[ansl]&&lr2[ans])||(l12[ansr]&&lr1[ans])))||(x1==1&&x2==0&&(l2r1[ans]||(r12[ansl]&&lr1[ans])||(l12[ansr]&&lr2[ans])))) printf("Y\n"); 
			else printf("N\n");
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值