皎月半洒花
2020-06-16 21:29:08
这题是真的????????!是十分有趣题目!
xyx 写在 CSDN 里的题解是俩 log 的,但其实只需要用一点「兔队线段树」的小技巧,就可以优化到一个 log。
大概首先是要对上面那个 easy version 的一些结论进行形式化的提炼和总结。考虑答案的本质。考虑把一个颜色
考虑用线段树快速维护这个东西。考虑需要维护什么信息:
1、需要维护分界点。即区间中被覆盖次数为
2、需要维护颜色数。即区间中出现次数最多的颜色。
3、但是
4、注意到要维护区间中出现次数的最大值,还要求连续且只有全局询问的话,有个小技巧。考虑让颜色
发现难以维护分界点?但是考虑到只有全局询问,于是可以借鉴兔队线段树里那个类似的思想。具体来说,发现对于线段树的根节点,有效信息是区间
具体细节方面,考虑维护区间中每段里颜色出现次数最大值
然后考虑修改操作,发现就是一个区间加再加一个单点维护。注意当
注意到颜色的修改可以再单独拿一个 set 来维护。最终复杂度
然后具体为什么能比 xyx 的做法少掉一个 log,个人认为是充分利用了『只有全局询问』这个性质,否则是不能用兔队线段树的 trick 的。
#include <set>
#include <cstdio>
const int N = 200005 ;
#define _be begin
#define _en rbegin
#define era erase
#define ins insert
using namespace std ;
set <int> col[N] ;
int seg[N * 3] ;
int mnv[N * 3] ;
int mxt[N * 3] ;
int tag[N * 3] ;
int lcon[N * 3] ;
int rcon[N * 3] ;
#define lc (rt << 1)
#define rc (rt << 1 | 1)
inline void _down(int rt){
if (tag[rt]){
mnv[lc] += tag[rt] ;
mnv[rc] += tag[rt] ;
tag[lc] += tag[rt] ;
tag[rc] += tag[rt] ;
tag[rt] = 0 ;
}
}
inline void _up(int rt){
int ls = rt << 1 ;
int rs = rt << 1 | 1 ;
mxt[rt] = max(mxt[ls], mxt[rs]) ;
mnv[rt] = min(mnv[ls], mnv[rs]) ;
if (mnv[ls] < mnv[rs]){
seg[rt] = seg[ls] ;
lcon[rt] = lcon[ls] ;
rcon[rt] = max(mxt[rs], rcon[ls]) ;
//此处由于最后要覆盖,所以 max_Time(rc) 本质上就是包含右端点的值。
}
else if (mnv[ls] > mnv[rs]){
seg[rt] = seg[rs] ;
rcon[rt] = rcon[rs] ;
lcon[rt] = max(mxt[ls], lcon[rs]) ;
}
else {
lcon[rt] = lcon[ls] ; rcon[rt] = rcon[rs] ;
seg[rt] = seg[ls] + seg[rs] + max(lcon[rs], rcon[ls]) ;
}
}
void upd(int rt, int l, int r, int ul, int ur, int v){
if (ul > ur) return ;
if (ul <= l && r <= ur)
return mnv[rt] += v, void(tag[rt] += v) ;
int mid = (l + r) >> 1 ; _down(rt) ;
if (ul <= mid) upd(lc, l, mid, ul, ur, v) ;
if (ur > mid) upd(rc, mid + 1, r, ul, ur, v) ;
_up(rt) ;
}
void cov(int rt, int l, int r, int p, int v){
if (l == r)
return void(mxt[rt] = lcon[rt] = v) ;
int mid = (l + r) >> 1 ; _down(rt) ;
if (p <= mid) cov(lc, l, mid, p, v) ;
else cov(rc, mid + 1, r, p, v) ; _up(rt) ;
}
int n, q ;
int base[N] ;
void mdf(int c, int mk){
int w ;
if (!(w = col[c].size())) return ;
// printf("%d %d %d %d %d\n", c, mk, *col[c]._be(), *-- col[c]._en(), (int)col[c].size()) ;
cov(1, 1, n, *col[c]._be(), mk > 0 ? w : 0) ;
upd(1, 1, n, *col[c]._be(), *col[c]._en() - 1, mk) ;
}
int val_it(){ return n - seg[1] - lcon[1] - rcon[1] ; }
int main(){
int x, y, z ;
scanf("%d%d", &n, &q) ;
for (int i = 1 ; i <= n ; ++ i)
scanf("%d", &base[i]), col[base[i]].ins(i) ;
for (int i = 1 ; i < N ; ++ i)
mdf(i, 1) ; printf("%d\n", val_it()) ;
while (q --){
scanf("%d%d", &x, &y) ; z = base[x] ;
mdf(z, -1) ; col[z].era(x) ; mdf(z, 1) ;
mdf(y, -1) ; col[y].ins(x) ; mdf(y, 1) ;
printf("%d\n", val_it()) ; base[x] = y ;
}
return 0 ;
}