NOIp训练 红绿色盲ldxcaicai(bit套主席树)

传送门
然而就是我把数颜色的数据加强了一下。。。
数据范围: n , m ≤ 200000 , a i ≤ 1000000 n,m\le200000,a_i\le1000000 n,m200000,ai1000000
而且还可以强制在线。。。
反正带修莫队是凉掉了。
正解是 b i t bit bit套主席树。
考虑用把每个位置上颜色出现的上一个位置作为下标插入到主席树中,然后答案就可以差分出来。
再套上 b i t bit bit就可以处理动态的情况。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
	static char buf[rlen],*ib,*ob;
	(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
	return ib==ob?-1:*ib++;
}
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
const int N=1e6+5,M=2e5+5;
int rt[N],n,m,a[N],pre[N],tot=0,mp[N<<1],las[N],idx[N];
set<int>S[N<<1];
typedef set<int>::iterator It;
namespace sgt{
    #define lc (son[p][0])
    #define rc (son[p][1])
    #define mid (l+r>>1)
    int siz[M*50],son[M*50][2],cnt=0;
    inline int lowbit(const int&x){return x&-x;}
    inline void update(int&p,int o,int l,int r,int k,int v){
        if(!p)p=++cnt;
        lc=son[o][0],rc=son[o][1],siz[p]=siz[o]+v;
        if(l==r)return;
        k<=mid?update(lc,son[o][0],l,mid,k,v):update(rc,son[o][1],mid+1,r,k,v);
    }
    inline int query(int p,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr)return siz[p];
        if(qr<=mid)return query(lc,l,mid,ql,qr);
        if(ql>mid)return query(rc,mid+1,r,ql,qr);
        return query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr);
    }
    inline void update(int p,int k,int v){for(ri i=p;i<=n;i+=lowbit(i))update(rt[i],rt[i],0,n,k,v);}
    inline int query(int p,int k){
        int ret=0;
        for(ri i=p;i;i-=lowbit(i))ret+=query(rt[i],0,n,0,k);
        return ret;
    }
    inline int ask(int l,int r){return query(r,l-1)-query(l-1,l-1);}
    #undef lc
    #undef rc
    #undef mid
}
inline void change(int x,int y){
    It it=S[a[x]].lower_bound(x);
    ++it;
    int aa,bb;
    aa=*it,bb=pre[*it];
    if(aa!=n+1){
        sgt::update(aa,bb,-1);
        bb=pre[*it]=pre[x];
        sgt::update(aa,bb,1);
    }
    S[a[x]].erase(x);
    it=S[y].lower_bound(x);
    aa=*it,bb=pre[*it];
    if(aa!=n+1){
        sgt::update(aa,bb,-1);
        pre[*it]=x;
        sgt::update(aa,x,1);
    }
    else bb=*(--it);
    sgt::update(x,pre[x],-1);
    pre[x]=bb;
    sgt::update(x,pre[x],1);
    S[y].insert(x);
    a[x]=y;
}
struct Qry{int op,a,b;}qry[N];
int main(){
	n=read(),m=read();
	for(ri i=1,val;i<=n;++i){
		a[i]=read();
		mp[++tot]=a[i];
	}
	for(ri i=1;i<=m;++i){
		char x=gc();
		while(!isalpha(x))x=gc();
		qry[i].op=x=='R';
		qry[i].a=read(),qry[i].b=read();
		if(x=='R')mp[++tot]=qry[i].b;
	}
	sort(mp+1,mp+tot+1),tot=unique(mp+1,mp+tot+1)-mp-1;
	for(ri i=1;i<=tot;++i)idx[mp[i]]=i;
	for(ri i=1;i<=tot;++i)S[i].insert(0),S[i].insert(n+1);
	for(ri i=1;i<=n;++i){
		a[i]=idx[a[i]];
		pre[i]=las[a[i]];
		sgt::update(i,pre[i],1);
		las[a[i]]=i;
		S[a[i]].insert(i);
	}
	for(ri i=1,a,b;i<=m;++i){
		if(qry[i].op==1)change(qry[i].a,idx[qry[i].b]);
		else cout<<sgt::ask(qry[i].a,qry[i].b)<<'\n';
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值