题意:询问区间唯一元素个数,单点修改。
分析:
借助Unique snowflakes, Can you answer these queries II的思想,唯一性可以借助元素上一次出现的位置来判断。
对于询问(x,y),只要回答[x,y)区间内,上一次出现位置prv[i] < x的元素数量即可。
对于修改来说,如果原来的a[x]的后继元素存在,则要修改后继的前驱。
a[x]修改成y以后,找到x位置前的y出现位置,作为x位置的前驱,并修改x位置以后下一个y的前驱。
寻找前驱后继可以用一个set保存(value,pos)的二元组,平方分解可以更暴力地找。
目前已知实现方法有三种,1.线段树套平衡树,2.平方分解,3.BIT套函数式线段树。
线段树套一个平衡树,想要偷懒试了试pb_ds里面的rb_tree,但是join的时候值域不能相交,并且只能nlognlogn建树。O((n+m)lognlogn)
改成套SBT,可以做到nlogn建线段树,然后写挂了。(实际上是我不知道SBT删除的时候怎么maintain。也许改成Treap或者BST会过。)。O(nlogn + mlognlogn)
平方分解,比较容易写,10s时限很稳。O(nlogn + m(N/BlogB+BlogB)) = O(nlogn + N^(3/2)log(N^(1/2)))
BIT套函数式,好写,内存消耗大(UVA的内存没有限制吗?)。O(nlogn,mlognlogn)
(实在过不了的话,因为暴力修改是O(1),可以水过...
#include<bits/stdc++.h> #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/tree_policy.hpp> using namespace std; using namespace __gnu_pbds; typedef pair<int,int> pii; typedef long long ll; const int maxn = 5e4+2; #define value first #define index second tree <pii,null_type> SET; #define para Node *(&o), int l = 0, int r = n #define lo (o->lch) #define ro (o->rch) #define Tvar int md = (l+r)>>1; #define lsn lo,l,md #define rsn ro,md,r #define insd x<=l&&r<=y const int maxd = 17; const int maxnds = maxd*maxn*maxd; struct Node { Node *lch,*rch; int s; }meo[maxnds]; int a[maxn]; int *const ps = (int*)(meo+1); int prv[maxn]; int n; Node *root[maxn]; Node *const nil = meo; Node *freeNode = nil; void build(int v,para) { *(++freeNode) = *o; o = freeNode; o->s++; if(r-l == 1) return; Tvar if(v < md) build(v,lsn); else build(v,rsn); } void inst(int v,int d,para) { if(o == nil){ *(++freeNode) = *o; o = freeNode; } o->s += d; if(r-l == 1) return; Tvar if(v < md) inst(v,d,lsn); else inst(v,d,rsn); } Node *BIT[maxn]; typedef vector<Node*> Prefix; Prefix X,Y; void q_pfx_bit(int x, Prefix &res) { res.clear(); while(x > 0){ res.push_back(BIT[x]); x &= x-1; } } void modify_bit(int x,int v,int d) { while(x <= n){ inst(v,d,BIT[x]); x += x&-x; } } inline int cal_lft(Prefix &p) { int cnt = 0; for(auto &nd: p){ cnt += nd->lch->s; } return cnt; } inline int cal_sum(Prefix &p) { int cnt = 0; for(auto &nd: p){ cnt += nd->s; } return cnt; } #define dump(P,ch) for(auto &nd: P){ nd = nd->ch; } int query(int v, int l = 0,int r = n) { if(r<=v) return cal_sum(Y)-cal_sum(X); Tvar if(v <= md) { dump(X,lch) dump(Y,lch) return query(v,l,md); } int tmp = cal_lft(Y)-cal_lft(X); dump(X,rch) dump(Y,rch) return tmp + query(v,md,r); } inline void modify(int x,int y) { modify_bit(x,prv[x],-1); modify_bit(x,prv[x]=y,1); } //#define LOCAL int main() { #ifdef LOCAL freopen("data.txt","r",stdin); #endif //cout<<maxnds; nil->lch = nil->rch = nil; root[0] = nil; int m; scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) { scanf("%d",a+i); prv[i] = ps[a[i]]; ps[a[i]] = i; SET.insert(pii(a[i],i)); } for(int i = 1; i <= n; i++){ root[i] = root[i-1]; build(prv[i],root[i]); } fill(BIT+1,BIT+n+1,nil); char op[2]; int x,y; while(m--){ scanf("%s%d%d",op,&x,&y); //0 based if(*op == 'Q'){ q_pfx_bit(x,X); q_pfx_bit(y,Y); X.push_back(root[x]); Y.push_back(root[y]); printf("%d ",query(x+1)); } else { x++; if(a[x] == y) continue; //... auto it = SET.lower_bound(pii(a[x],x+1)); if(it != SET.end() && it->value == a[x]){ modify(it->index,prv[x]); } it = SET.lower_bound(pii(y,x));//找后继,需要保证(y,x)不存在 if(it != SET.end() && it->value == y){ modify(it->index,x); } modify(x,(it != SET.begin() && (--it)->value == y)? it->index : 0); SET.erase(pii(a[x],x)); SET.insert(pii(a[x] = y,x)); } } return 0; }