LOJ#557. 「Antileaf's Round」你这衣服租来的吗(FHQ Treap+珂朵莉树)

题面

传送门

题解

好吧我是不太会复杂度分析……

我们对于每种颜色用一个数据结构维护(比方说线段树或者平衡树,代码里写的平衡树),那么区间询问很容易就可以解决了

所以现在的问题是区间修改,如果区间颜色相等直接\(O(\log n)\)修改就好了,否则的话,一个很暴力的思路是把区间分成若干段颜色相等的部分,每一个部分都直接\(O(\log n)\)修改

乍看这样是\(gg\)的,但是我们仔细观察一下,每一次修改的时候只有相邻两段颜色不同的时候会贡献\(O(\log n)\)的复杂度,而初始时段数是\(O(n)\)的,每一次修改的时候增加的段数是常数,所以总的复杂度是\(O((n+m)\log n)\)

ps:因为修改的时候要暴力跳区间需要资瓷查询某个点的颜色所以写了个珂朵莉树

pps:虽然说起来很简单但是调起来非常麻烦……

//minamoto
#include
#define R register
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;iI;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
templateinline bool cmax(T&a,const T&b){return ainline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int K=-1,Z=0;
inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
void print(R int x){
    if(K>1<<20)Ot();if(x<0)sr[++K]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++K]=z[Z],--Z);sr[++K]='\n';
}
inline char getop(){R char ch;while((ch=getc())>'Z'||ch<'A');return ch;}
unsigned int aaa=19260817;
inline unsigned int rd(){aaa^=aaa>>15,aaa+=aaa<<12,aaa^=aaa>>3;return aaa;}
const int N=5e5+5;
struct node;typedef node* ptr;
struct node{
	ptr lc,rc;int v,sz;unsigned int pr;
	inline ptr init(R int val){return v=val,sz=1,pr=rd(),this;}
	inline ptr upd(){return sz=lc->sz+rc->sz+1,this;}
}e[N],*pp=e,*pl,*pr;maprt;
inline ptr newnode(R int v){return ++pp,pp->lc=pp->rc=e,pp->init(v);}
void split(ptr p,int k,ptr &s,ptr &t){
	if(p==e)return s=t=e,void();
	if(p->v<=k)s=p,split(p->rc,k,p->rc,t);
		else t=p,split(p->lc,k,s,p->lc);
	p->upd();
}
ptr merge(ptr s,ptr t){
	if(s==e)return t;if(t==e)return s;
	if(s->prpr)return s->rc=merge(s->rc,t),s->upd();
	return t->lc=merge(s,t->lc),t->upd();
}
int n,m,lasans,a[N];
struct zz{
	int l,r;mutable int v;
	inline zz(R int li,R int ri=0,R int vi=0):l(li),r(ri),v(vi){}
	inline bool operator <(const zz &b)const{return ls;typedef set::iterator IT;
IT split(int pos){
	IT it=s.lower_bound(zz(pos));
	if(it!=s.end()&&it->l==pos)return it;
	--it;int l=it->l,r=it->r,v=it->v;
	s.erase(it),s.insert(zz(l,pos-1,v));
	return s.insert(zz(pos,r,v)).first;
}
void update(int l,int r,int v){
	IT itr=split(r+1),itl=split(l);
	s.erase(itl,itr),s.insert(zz(l,r,v));
}
int ask(int pos){
	IT it=s.lower_bound(zz(pos));
	if(it==s.end()||it->l!=pos)--it;
	return it->v;
}
int Kth(ptr p,int k){
	if(p->lc->sz==k-1)return p->v;
	if(p->lc->sz>=k)return Kth(p->lc,k);
	return Kth(p->rc,k-p->lc->sz-1);
}
int query(ptr &rt,int l,int r,int k){
	ptr s,t,p,q;
	split(rt,l-1,s,t),split(t,r,p,q);
	int now=p->sz>=k?Kth(p,k):0;
	return rt=merge(s,merge(p,q)),now;
}
void divide(ptr p,int k,int r,ptr &s,ptr &t){
	if(p==e)return s=t=e,void();
	if(p->lc->sz+k==p->v&&p->v<=r)s=p,divide(p->rc,k+p->lc->sz+1,r,p->rc,t);
		else t=p,divide(p->lc,k,r,s,p->lc);
	p->upd();
}
int change(ptr &p,int k,int r){
	ptr s,t,f,g;int now;
	split(p,k-1,f,g),divide(g,k,r,s,t);
	now=Kth(s,s->sz),p=merge(f,t),pl=merge(pl,s);
	return now+1;
}
int main(){
//	freopen("gold1.in","r",stdin);
	n=read(),m=read(),lasans=0,e->lc=e->rc=e;
	fp(i,1,n){
		a[i]=read();if(rt[a[i]]==NULL)rt[a[i]]=e;
		rt[a[i]]=merge(rt[a[i]],newnode(i));
		s.insert(zz(i,i,a[i]));
	}
	for(int op,l,r,v,k,tl,tr,c;m;--m){
		op=getop(),l=read()^lasans,r=read()^lasans;
		if(op=='M'){
			v=read()^lasans,tl=l,tr=r;if(rt[v]==NULL)rt[v]=e;
			split(rt[v],l-1,pl,pr),split(pr,r,rt[v],pr);
			while(tl<=tr)c=ask(tl),tl=change(rt[c],tl,r);
			rt[v]=merge(pl,pr);
			update(l,r,v);
		}else{
			k=read()^lasans,v=read()^lasans;if(rt[v]==NULL)rt[v]=e;
			print(lasans=query(rt[v],l,r,k));
		}
	}
	return Ot(),0;
}

你可能感兴趣的:(LOJ#557. 「Antileaf's Round」你这衣服租来的吗(FHQ Treap+珂朵莉树))