大江东去,浪淘尽,千古风流人物。故垒西边,人道是,三国周郎赤壁。乱石穿空,惊涛拍岸,卷起千堆雪。江山如画,一时多少豪杰。遥想公瑾当年,小乔初嫁了,雄姿英发。羽扇纶巾,谈笑间,樯橹灰飞烟灭。故国神游,多情应笑我,早生华发。人生如梦,一尊还酹江月。

高手训练 线段树T3 P1753:区间连通性

线段树/标记永久化

复杂度 \(O(nlogn)\)

题解有误,并非所有与线段树节点[l,r]相交的所有区间[s.t]都要存入vector

插入区间[s,t]时,我们覆盖了一段完整的区间,如图

实质上是覆盖了表面的一层,即标记不下传

故我们merge时要考虑每一层的vector

插入时,如果两个区间恰好相接,也视作互相到达,所以合并时用(s,t)合并,插入时用[s+1,t-1]插入

由于区间按长度从小到大插入,故不存在这样的情况:

故merge的区间一定是两两可达的,用并查集来维护这种关系

最后,若区间存在包含关系,则A可以到达B,B不能到达A(一端端点重合也算),则特判即可,由于端点可能重合,故不能只判断一个端点

代码非常简单:

#include<bits/stdc++.h>
using namespace std;

#define go(i,a,b) for(int i=a;i<=b;++i)
#define com(i,a,b) for(int i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define ls rt<<1
#define rs rt<<1|1

const int inf=0x3f3f3f3f,N=2e5+10;

int n,m,op[N],a[N],b[N],c[N],d[N],f[N],rk[N],id,tot;
vector<int>inter[N<<2];

void read(int &x){
	x=0;char c=getchar(),f=1;
	while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); }
	while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); }
	x*=f;
}
inline int find(int x){ return f[x]=f[x]==x?x:find(f[x]); }

void merge(int rt,int l,int r,int k){
	for(int i=0;i<inter[rt].size();++i){
		int x=inter[rt][i];
		x=find(x);
		f[x]=id;
		c[id]=min(c[id],c[x]);
		d[id]=max(d[id],d[x]);
	}
	inter[rt].clear();
	if(l==r) return;
	int mid=l+r>>1;
	if(k<=mid) merge(ls,l,mid,k);
	else merge(rs,mid+1,r,k);
}

void insert(int rt,int l,int r,int x,int y,int k){
	if(l>=x&&r<=y){
		inter[rt].push_back(k);
		return; 
	}
	int mid=l+r>>1;
	if(x<=mid) insert(ls,l,mid,x,y,k);
	if(y>mid) insert(rs,mid+1,r,x,y,k);
}

int main(){
	//freopen("input.txt","r",stdin);
	read(n);
	go(i,1,n){
		read(op[i]),read(a[i]),read(b[i]);
		if(op[i]==1) rk[++tot]=a[i],rk[++tot]=b[i];
	}
	sort(rk+1,rk+tot+1);
	tot=unique(rk+1,rk+tot+1)-rk-1;
	go(i,1,n) if(op[i]==1){
		a[i]=lower_bound(rk+1,rk+tot+1,a[i])-rk;
		b[i]=lower_bound(rk+1,rk+tot+1,b[i])-rk;
	}
	int x,y;
	go(i,1,n){
		if(op[i]==1){
			f[++id]=id,c[id]=a[i],d[id]=b[i];
			merge(1,1,tot,a[i]);
			merge(1,1,tot,b[i]);
			insert(1,1,tot,c[id]+1,d[id]-1,f[id]);
		}
		else{
			x=find(a[i]),y=find(b[i]);
			if(x==y) puts("YES");
			else{
				if(c[x]>c[y]&&c[x]<d[y]||d[x]>c[y]&&d[x]<d[y]) puts("YES");
				else puts("NO");
			}
		}
	}
	return 0;
}
posted @ 2019-09-25 12:03  White_star  阅读(276)  评论(0编辑  收藏  举报
}