线段树合并区间+启发式合并。
针对合并操作,如果暴力合并,复杂度显然是O(n2)的,尝试用启发式合并优化它。 用数组维护每种颜色的位置个数,合并时,将个数少的颜色全部修改成个数多的颜色。 由于具体实现仍与暴力合并类似,因此可以轻易地维护前面提到的树状数组。 需要注意的是,由于合并时可能交换颜色,因此还需要维护每个数代表的真实颜色。 由于采用了启发式合并,因此时间复杂度为O(nlogn+Qlog2n)或O(nlogn+Qlogn)。 本题也可以用线段树或其他很多数据结构解决。
代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+5, MAXCOLOR = 1e6+5;
int qx, qy, color[MAXCOLOR];
struct node {
int l, r, val;
}a[5*MAXN];
vector<int> record[MAXCOLOR];
void ini() {
for(int i = 0; i < MAXCOLOR; i++) record[i].clear(), color[i] = i;
}
void mantain(int o, int l, int r) {
int lson = o<<1, rson = o<<1|1;
a[o].l = a[lson].l;
a[o].r = a[rson].r;
a[o].val = a[lson].val+a[rson].val;
if(a[lson].r == a[rson].l) a[o].val--;
}
void build(int o, int l, int r) {
if(l == r) {
scanf("%d", &a[o].l);
a[o].r = a[o].l;
a[o].val = 1;
record[a[o].l].push_back(l);
return;
}
int m = (l+r)>>1;
build(o<<1, l, m);
build(o<<1|1, m+1, r);
mantain(o, l, r);
}
int query(int o, int l, int r) {
int lson = o<<1, rson = o<<1|1, ql = qx, qr = qy;
if(l>=ql && r<=qr) return a[o].val;
int m = (l+r)>>1, sum = 0, cnt = 0;
if(m < qr) sum += query(rson, m+1, r), cnt++;
if(m >= ql) sum += query(lson, l, m), cnt++;
if(cnt==2 && a[lson].r==a[rson].l) sum--;
return sum;
}
void update(int o, int l, int r, int p, int y) {
int lson = o<<1, rson = o<<1|1, m = (l+r)>>1;
if(l == r) {
a[o].l = a[o].r = y;
return;
}
if(m < p) update(rson, m+1, r, p, y);
else update(lson, l, m, p, y);
mantain(o, l, r);
}
int main() {
int T;
cin >> T;
while(T--) {
ini();
int n, q;
scanf("%d%d", &n, &q);
build(1, 1, n);
while(q--) {
int op;
scanf("%d%d%d", &op, &qx, &qy);
if(op == 1) {
int x = color[qx], y = color[qy];
if(x == y) continue;
if(record[x].size() < record[y].size()) {
for(int i = 0; i < record[x].size(); i++) {
int pos = record[x][i];
update(1, 1, n, pos, y);
record[y].push_back(pos);
}
record[x].clear();
}
else {
color[qy] = x, color[qx] = y;
for(int i = 0; i < record[y].size(); i++) {
int pos = record[y][i];
update(1, 1, n, pos, x);
record[x].push_back(pos);
}
record[y].clear();
}
}
else printf("%d\n", query(1, 1, n));
}
}
return 0;
}