题意
给一个长度为n的序列,每次操作会把区间中的x改成y。问m次操作后的序列长什么样。
n,m<=200000,x,y<=100
分析
第一次见识到原来线段树还有分裂这种骚操作。
就是对每种权值开一棵线段树,然后每次把x线段树里面的对应子树和y线段树合并即可。
代码
#include <bits/stdc++.h>
const int N = 200005;
const int M = 105;
int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
struct Tree
{
int l,r;
}t[N * 20];
int rt[M];
int L,R;
int sz;
void insert(int &d,int l,int r,int x)
{
if (!d)
d = ++sz;
if (l == r)
return;
int mid = (l + r) >> 1;
if (x <= mid)
insert(t[d].l, l, mid, x);
else insert(t[d].r, mid + 1, r, x);
}
int merge(int x,int y)
{
if (!x || !y)
return x + y;
t[x].l = merge(t[x].l, t[y].l);
t[x].r = merge(t[x].r, t[y].r);
return x;
}
void change(int &d,int &p,int l,int r)
{
if (!d)
return;
if (L <= l && r <= R)
{
p = merge(d, p);
d = 0;
return;
}
if (!p)
p = ++sz;
int mid = (l + r) >> 1;
if (L <= mid)
change(t[d].l, t[p].l, l, mid);
if (R > mid)
change(t[d].r, t[p].r, mid + 1, r);
}
int ans[N];
int now;
void solve(int p,int l,int r)
{
if (!p)
return;
if (l == r)
{
ans[l] = now;
return;
}
int mid = (l + r) >> 1;
solve(t[p].l, l, mid);
solve(t[p].r, mid + 1, r);
}
int main()
{
int n = read();
for (int i = 1; i <= n; i++)
{
int x = read();
insert(rt[x], 1, n, i);
}
int m = read();
for (int i = 1; i <= m; i++)
{
L = read(), R = read(); int x = read(), y = read();
if (x != y)
change(rt[x], rt[y], 1, n);
}
for (int i = 1; i <= 100; i++)
now = i, solve(rt[i], 1, n);
for (int i = 1; i <= n; i++)
printf("%d ",ans[i]);
}