[Tkey] 黑兔子,白兔子

CL-21

一般拿到这个题第一眼都应该能看出并查集,subtask1 是给并查集暴力修改的.

后面 subtask2 没有联通操作,是给纯线段树的,也算是启发正解了

再往下可以考虑操作 \(1\) 采用线段树区间修改,操作 \(2\) 采用并查集维护的思路. 按这个思路去想,那么操作 \(2\) 肯定不能进行修改,因为我们无法快速知道哪些元素在本并查集里,就算知道,暴力去修改也容易被卡到 \(O(n)\). 既然这样的话,考虑到同一个并查集里的元素都相等,因此我们就考虑用并查集里的代表元素去表示这个并查集最终的颜色,这样我们在操作二中仅需修改一个点即可.

因为我们懒惰地进行了操作二,现在的问题就是如何去判断一个并查集里的最终颜色到底是哪个,根据颜色会进行覆盖的思想,我们给每个颜色再开一个时间戳,表示该颜色被修改的顺序,这样我们仅需要在最后遍历一遍线段树叶节点,找出哪个颜色的时间戳最大,就把它作为该并查集的颜色.

有一些需要注意的细节,请注意你最后扫的那一遍是否为不完全更新. 一开始的 STD 就是因为在扫的时候不完全更新了,因此最后挂了八十多分. 我对此的解决办法是扫两遍,也许大家还有更好的策略.

还有一些不必要的小优化,其实因为这个线段是只在最后询问一次,所以在更新操作的时候完全没必要 pushdown(),直接覆盖就行了.

#include<bits/stdc++.h>
using namespace std;
const int N=1000001;
int n,m,k;
int root[N],tagroot[N],ans[N];
namespace dsu{
	int p[N];
	void clear(){
		for(int i=1;i<=n;++i){
			p[i]=i;
			tagroot[i]=1;
			root[i]=1;
		}
	}
	int find(int id){
		if(p[id]==id){
			return id;
		}
		p[id]=find(p[id]);
		return p[id];
	}
}
namespace stree{
	#define tol (id*2)
	#define tor (id*2+1)
	#define mid(l,r) mid=((l)+(r))/2
	struct tree{
		int tag,lazy;
		int l,r;
	}t[4*N];
	void build(int id,int l,int r){
		t[id].l=l;t[id].r=r;
		if(l==r) return;
		int mid(l,r);
		build(tol,l,mid);
		build(tor,mid+1,r);
	}
	void update(int id,int l,int r,int k,int tt){
		if(t[id].l>t[id].r or t[id].r<l or t[id].l>r) return;
		if(t[id].l>=l and t[id].r<=r){
			t[id].lazy=k;
			t[id].tag=tt;
			return;
		}
		int mid(t[id].l,t[id].r);
		update(tol,l,r,k,tt);
		update(tor,l,r,k,tt);
	}
	void pushdown(int id){
		if(t[id].tag>t[tol].tag){
			t[tol].lazy=t[id].lazy;
			t[tol].tag=t[id].tag;
		}
		if(t[id].tag>t[tor].tag){
			t[tor].lazy=t[id].lazy;
			t[tor].tag=t[id].tag;
		}
	}
	void release(int id){
		if(t[id].l==t[id].r){
			int x=dsu::find(t[id].l);
			if(tagroot[x]>t[id].tag){
				ans[t[id].l]=root[x];
			}
			else{
				ans[t[id].l]=t[id].lazy;
				tagroot[x]=t[id].tag;
				root[x]=t[id].lazy;
			}
			return;
		}
		pushdown(id);
		release(tol);
		release(tor);
	}
}
int main(){
	cin>>n>>m>>k;
	dsu::clear();
	int op,l,r,x;
	stree::build(1,1,n);
	for(int i=1;i<=m;++i){
		cin>>op>>l>>r>>x;
		if(op==1){
			stree::update(1,l,r,x,i+1);
		}
		else{
			int a=dsu::find(l),b=dsu::find(r);
			root[b]=x;
			tagroot[b]=i+1;
			if(a!=b){
				dsu::p[a]=b;
			}
		}
	}
	stree::release(1);
	stree::release(1);
	for(int i=1;i<=n;++i){
		cout<<ans[i]<<" ";
	}
	cout<<endl;
} 
posted @ 2024-07-24 21:15  HaneDaniko  阅读(13)  评论(1编辑  收藏  举报