给出一个数列,有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;
}