CF911G Mass Change Queries- 动态开点线段树

给出一个数列,有q个操作,每种操作是把区间[l,r]中等于x的数改成y.输出q步操作完的数列.
https://www.luogu.com.cn/problem/CF911G
输入 #1 复制
5
1 2 3 4 5
3
3 5 3 5
1 5 5 1
1 5 1 5
输出 #1 复制
5 2 5 4 5


题解

  • 线段树动态开点板题(线段树合并)

代码

#include <iostream>
#include <cstdio>
using namespace std;
int n,cnt,ans[200003],root[200003];
struct fdfdfd{int l,r;}a[10000003];
void add(int &x,int left,int right,int d)
{
	if(left>d||right<d) return;
	if(!x) x=++cnt;
	if(left==right) return;
	int mid=(left+right)>>1;
	add(a[x].l,left,mid,d); add(a[x].r,mid+1,right,d);
}
int merge(int x,int y)
{
	if(!x||!y) return x|y;
	a[x].l=merge(a[x].l,a[y].l);
	a[x].r=merge(a[x].r,a[y].r);
	return x;
}
void modify(int &x,int &y,int left,int right,int dx,int dy)
{
	if(!x||left>dy||right<dx) return;
	if(left>=dx&&right<=dy) {y=merge(x,y),x=0; return;}
	if(!y) y=++cnt;
	int mid=(left+right)>>1;
	modify(a[x].l,a[y].l,left,mid,dx,dy);
	modify(a[x].r,a[y].r,mid+1,right,dx,dy);
}
void change(int x,int left,int right,int col)
{
	if(!x) return;
	if(left==right) {ans[left]=col; return;}
	int mid=(left+right)>>1;
	change(a[x].l,left,mid,col); change(a[x].r,mid+1,right,col);
}
int main()
{
	scanf("%d",&n);
	for(int i=1,x;i<=n;++i) scanf("%d",&x),add(root[x],1,n,i);
	int m; scanf("%d",&m);
	for(int i=1,x,y,l,r;i<=m;++i)
	{
		scanf("%d%d%d%d",&l,&r,&x,&y);
		if(x!=y) modify(root[x],root[y],1,n,l,r);
	}
	for(int i=1;i<=100;++i) change(root[i],1,n,i);
	for(int i=1;i<=n;++i) cout<<ans[i]<<' ';
	return 0;
}
posted @ 2020-12-24 15:45  wuwendongxi  阅读(98)  评论(0编辑  收藏  举报