P8996 [CEOI 2022] Abracadabra 题解

P8996 [CEOI 2022] Abracadabra 题解


知识点

线段树,平衡树,树状数组。

分析

首先,我们可以分析一下样例。

洗牌次数 自底向上的牌堆
\(0\) \(7\ 5\ 2\ 9\ 10\ 8\ 4\ 3\ 6\ 1\)
\(1\) \(7\ 5\ 2\ 8\ 4\ 3\ 6\ 1\ 9\ 10\)
\(2\) \(3\ 6\ 1\ 7\ 5\ 2\ 8\ 4\ 9\ 10\)
\(3\) \(2\ 3\ 6\ 1\ 7\ 5\ 8\ 4\ 9\ 10\)

分段

我们将第 \(0\) 次与第 \(1\) 次作比较,发现两次都有几段连续的数:

洗牌次数 自底向上的牌堆
\(0\) \(7\ 5\ 2\mid 9\ 10\mid 8\ 4\ 3\ 6\ 1\)
\(1\) \(7\ 5\ 2\mid 8\ 4\ 3\ 6\ 1\mid 9\ 10\)

我们可以先凭最表面的分段,就会分成上面两种,发现第 \(1\) 次就是第 \(0\) 次分段后按第一个数排序。

而每段又有什么规律呢?好像有两段第一个数都是最大的,而另一段是 \(9\ 10\),似乎不符合规律,但是我们又可以把上面的分成:

洗牌次数 自底向上的牌堆
\(0\) \(7\ 5\ 2\ \mid 9 \mid 10\mid 8\ 4\ 3\ 6\ 1\)
\(1\) \(7\ 5\ 2\mid 8\ 4\ 3\ 6\ 1\mid 9\mid 10\)

这下就符合规律了。

拆段

再考虑 \(1\) 次时到第 \(2\) 次,我们按照上面的方式来分段:

洗牌次数 自底向上的牌堆
\(1\) \(7\ 5\ 2\mid 8\ 4\mid 3\ 6\ 1\mid 9\mid 10\)
\(2\) \(3\ 6\ 1\mid 7\ 5\ 2\mid 8\ 4\mid 9\mid 10\)

这好像就是把上面横跨中间的分开就好了,但是我们换一个样例看一下:

洗牌次数 自底向上的牌堆
\(0\) $9 \ 7\ 5\ 2\ 10 \ 8 \ 4\ 3\ 6\ 1\ $
\(1\) \(9 \ 7\ 5\ 2\ 8\ 4\ 3\ 6\ 1\ 10\)
\(2\) \(3\ 6\ 1\ 4\ 8\ 9 \ 7\ 5\ 2\ 10\)
  • \(0 \to 1\)

    洗牌次数 自底向上的牌堆
    \(0\) $9 \ 7\ 5\ 2\mid 10\mid 8 \ 4\ 3\ 6\ 1\ $
    \(1\) \(9 \ 7\ 5\ 2\mid 8\ 4\ 3\ 6\ 1\mid 10\)
  • \(1 \to 2\)

    洗牌次数 自底向上的牌堆
    \(1\) \(9 \ 7\ 5\ 2\mid 8\mid 4\mid 3\ 6\ 1\mid 10\)
    \(2\) \(3\ 6\ 1\mid 4\mid 8\mid 9 \ 7\ 5\ 2\mid 10\)

除了分开横跨中间的部分,我们还要把分开的后面那段给按照一开始分段的方法分开,这里我们可以处理出对于每个值下一个大于它的值是多少,然后一路处理过去,均摊次数是线性的。

那么我们就可以动态模拟维护了。

实现

考虑套数据结构进行动态维护。

平衡树

最简单的思想,把区间存在平衡树中,用一些操作解决即可。

这里选用无旋 Treap,那么实现按值分裂、按大小分裂和分裂第一个节点即可。

线段树 & 树状数组

由于对每段排序是按照每段第一个值大小升序排序,而且我们只要求按大小查值,所以我们可以用权值线段树或树状数组代替,只需实现单点修改,线段树二分或树状数组倍增以及前缀和查询即可。

代码

平衡树

//#define Plus_Cat ""
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define Fi first
#define Se second
#define Pii pair<int,int>
#define uint unsigned int
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define FOR(i,a,b) for(int i(a);i<=(int)(b);++i)
#define DOR(i,a,b) for(int i(a);i>=(int)(b);--i)
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define EDGE(g,i,x,y) for(int i=(g).h[(x)],y=(g)[(i)].v;~i;y=(g)[(i=(g)[i].nxt)>0?i:0].v)
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);return Main();}signed Main
using namespace std;
constexpr int N(2e5+10),Qr(1e6+10);
mt19937 rng(random_device {}());

namespace IOEcat {
    //Fast IO
} using namespace IOEcat;

bool flag;
int n,Q;
int a[N],len[N],nxt[N],pos[N],ans[Qr];
vector<Pii> vec[N];

struct Treap {
	int rt,tot;
	struct node {
		int key,cnt,siz,ls,rs;
		uint blc;
		node(int key=0,int cnt=0,int siz=0,int ls=0,int rs=0,uint blc=rng()):
			key(key),cnt(cnt),siz(siz),ls(ls),rs(rs),blc(blc) {}
	} tr[N];

	node &operator [](int i) { return tr[i]; }

	Treap():rt(0),tot(0) {}
#define ls(p) (tr[p].ls)
#define rs(p) (tr[p].rs)
	void Init() { tr[rt=tot=1]=node(); }

	int New(int key,int cnt) { return tr[++tot]=node(key,cnt,cnt),tot; }

	void Up(int p) { tr[p].siz=tr[ls(p)].siz+tr[p].cnt+tr[rs(p)].siz; }

	int &Merge(int &o,int p,int q) {
		if(!p||!q)return o=p|q;
		return (tr[p].blc<=tr[q].blc?Merge(rs(o=p),rs(p),q):Merge(ls(o=q),p,ls(q))),Up(o),o;
	}

	void Split_key(int &o,int &p,int key) { //[<=key] -> o,[>key] -> p
		if(!p)return o=0,void();
		if(key<tr[p].key)return Split_key(o,ls(p),key),Up(p);
		if(key==tr[p].key)return o=p,p=rs(p),rs(o)=0,Up(o);
		return o=p,Split_key(rs(o),p=rs(o),key),Up(o);
	}

	void Split_siz(int &o,int &p,int siz) { //[<=siz] -> o,[>siz] -> p
		if(!p)return o=0,void();
		if(tr[ls(p)].siz+tr[p].cnt<=siz)
			return o=p,Split_siz(rs(o),p=rs(o),siz-tr[ls(p)].siz-tr[p].cnt),Up(o);
		return Split_siz(o,ls(p),siz),Up(p);
	}

	void Split_begin(int &o,int &p) { //[begin] -> o,[otherwise] -> p
		if(!p)return o=0,void();
		if(ls(p))return Split_begin(o,ls(p)),Up(p);
		return o=p,p=rs(p),rs(o)=0,Up(o),void();
	}

	int Kth(int p,int k) {
		if(!p)return 0;
		if(ls(p)&&k<=tr[ls(p)].siz)return Kth(ls(p),k);
		if(k<=tr[ls(p)].siz+tr[p].cnt)return a[pos[tr[p].key]+k-tr[ls(p)].siz-1];
		return Kth(rs(p),k-tr[ls(p)].siz-tr[p].cnt);
	}

	void Print(int p,int fa=-1,int sign=-1) {
		if(!p)return;
		Print(ls(p),p,0);
		DE(p,fa,sign,tr[p].key);
		Print(rs(p),p,1);
	}
#undef ls
#undef rs
} trp;

signed main() {
#ifdef Plus_Cat
	freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
	/*DE("Input");*/
	I(n,Q);
	FOR(i,1,n)I(a[i]);
	/*DE("Offline");*/
	FOR(i,1,Q) {
		int t,x;
		I(t,x),t?vec[min(n,t)].push_back({x,i}),0:ans[i]=a[x];
	}
	/*DE("Init");*/
	//len
	auto Init_len=[&](int L,int R) {
		int it(L);
		FOR(i,L+1,R)if(a[i]>a[it])len[a[it]]=i-it,it=i;
		len[a[it]]=R-it+1;
	};
	Init_len(1,n>>1),Init_len((n>>1)+1,n);
	//Treap
	trp.Init();
	FOR(i,1,n)if(len[i])trp.Merge(trp.rt,trp.rt,trp.New(i,len[i]));
	//nxt
	set<int> st;
	DOR(i,n,1) {
		auto it(st.upper_bound(a[i]));
		nxt[a[i]]=(it==st.end()?n+1:*it),st.insert(a[i]);
		while(!st.empty()&&*st.begin()<a[i])st.erase(st.begin());
	}
	//pos
	FOR(i,1,n)pos[a[i]]=i;
	pos[n+1]=n+1;
	/*DE("Solve");*/
	FOR(i,1,n) {
		for(const Pii &p:vec[i])ans[p.Se]=trp.Kth(trp.rt,p.Fi);
		if(flag)continue;
		int l(0),mid(0),r(trp.rt);
		trp.Split_siz(l,r,n>>1);
		if(trp[l].siz==(n>>1)&&(trp.Merge(trp.rt,l,r),flag=true))continue;
		int pla(trp[trp.Split_begin(mid,r),mid].key);
		trp[mid].cnt=trp[mid].siz=(n>>1)-trp[l].siz;
		for(int p(a[pos[pla]+(n>>1)-trp[l].siz]); p<=n&&pos[p]<pos[pla]+len[pla]; p=nxt[p]) {
			len[p]=min(pos[pla]+len[pla],pos[nxt[p]])-pos[p];
			int L(0),R(l);
			trp.Split_key(L,R,p),trp.Merge(l,L,trp.Merge(R,trp.New(p,len[p]),R));
		}
		len[pla]=trp[mid].cnt,trp.Merge(trp.rt,l,trp.Merge(r,mid,r));
	}
	/*DE("Output");*/
	FOR(i,1,Q)O(ans[i],'\n');
	return 0;
}

线段树

//#define Plus_Cat ""
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define Fi first
#define Se second
#define Pii pair<int,int>
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define FOR(i,a,b) for(int i(a);i<=(int)(b);++i)
#define DOR(i,a,b) for(int i(a);i>=(int)(b);--i)
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define EDGE(g,i,x,y) for(int i=(g).h[(x)],y=(g)[(i)].v;~i;y=(g)[(i=(g)[i].nxt)>0?i:0].v)
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);return Main();}signed Main
using namespace std;
constexpr int N(2e5+10),Qr(1e6+10);

namespace IOEcat {
    //Fast IO
} using namespace IOEcat;

int n,Q;
int a[N],len[N],nxt[N],pos[N],ans[Qr];
vector<Pii> vec[N];

struct SEG {
#define ls (p<<1)
#define rs (p<<1|1)
#define mid ((l+r)>>1)
	int tr[N<<2];

	void Up(int p) { tr[p]=tr[ls]+tr[rs]; }

	void Build(int p=1,int l=1,int r=n) {
		if(l==r)return tr[p]=len[l],void();
		Build(ls,l,mid),Build(rs,mid+1,r),Up(p);
	}

	void Change(int x,int d,int p=1,int l=1,int r=n) {
		if(l==r)return tr[p]=d,void();
		return (x<=mid?Change(x,d,ls,l,mid):Change(x,d,rs,mid+1,r)),Up(p);
	}

	int Binary(int k=(n>>1),int p=1,int l=1,int r=n) {
		if(l==r)return l;
		if(tr[rs]>=k)return Binary(k,rs,mid+1,r);
		return Binary(k-tr[rs],ls,l,mid);
	}

	int Sum(int L,int R,int p=1,int l=1,int r=n) {
		if(L<=l&&r<=R)return tr[p];
		if(R<=mid)return Sum(L,R,ls,l,mid);
		if(mid<L)return Sum(L,R,rs,mid+1,r);
		return Sum(L,R,ls,l,mid)+Sum(L,R,rs,mid+1,r);
	}
#undef ls
#undef rs
#undef mid
} seg;

signed main() {
#ifdef Plus_Cat
	freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
	/*DE("Input");*/
	I(n,Q);
	FOR(i,1,n)I(a[i]);
	FOR(i,1,Q) {
		int t,x;
		I(t,x),t?vec[min(n,t)].push_back({x,i}),0:ans[i]=a[x];
	}
	/*DE("Init");*/
	//pos
	FOR(i,1,n)pos[a[i]]=i;
	pos[n+1]=n+1;
	//left
	int it(1);
	FOR(i,2,n>>1)if(a[i]>a[it])len[a[it]]=i-it,it=i;
	len[a[it]]=(n>>1)-it+1;
	//right
	it=(n>>1)+1;
	FOR(i,(n>>1)+2,n)if(a[i]>a[it])len[a[it]]=i-it,it=i;
	len[a[it]]=n-it+1;
	//nxt
	set<int> st;
	DOR(i,n,1) {
		nxt[a[i]]=(st.upper_bound(a[i])==st.end()?n+1:*st.upper_bound(a[i])),st.insert(a[i]);
		while(!st.empty()&&*st.begin()<a[i])st.erase(st.begin());
	}
	//seg
	seg.Build();
	/*DE("Solve");*/
	FOR(i,1,n) {
		for(const Pii &p:vec[i]) {
			int x(p.Fi),pla(seg.Binary(n-x+1));
			if(pla>1)x-=seg.Sum(1,pla-1);
			ans[p.Se]=a[pos[pla]+x-1];
		}
		int pla(seg.Binary()),sum(pla>1?seg.Sum(1,pla-1):0);
		if(sum==(n>>1))continue;
		for(int p(a[pos[pla]+(n>>1)-sum]); p&&p<=n&&pos[p]<pos[pla]+len[pla]; p=nxt[p])
			seg.Change(p,len[p]=min(pos[pla]+len[pla],pos[nxt[p]])-pos[p]);
		seg.Change(pla,len[pla]=(n>>1)-sum);
	}
	/*DE("Output");*/
	FOR(i,1,Q)O(ans[i],'\n');
	return 0;
}

树状数组

//#define Plus_Cat ""
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define Fi first
#define Se second
#define Pii pair<int,int>
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define FOR(i,a,b) for(int i(a);i<=(int)(b);++i)
#define DOR(i,a,b) for(int i(a);i>=(int)(b);--i)
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define EDGE(g,i,x,y) for(int i=(g).h[(x)],y=(g)[(i)].v;~i;y=(g)[(i=(g)[i].nxt)>0?i:0].v)
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);return Main();}signed Main
using namespace std;
constexpr int N(2e5+10),Qr(1e6+10);

namespace IOEcat {
    //Fast IO
} using namespace IOEcat;

bool flag;
int n,Q,L;
int a[N],len[N],nxt[N],pos[N],ans[Qr];
vector<Pii> vec[N];

struct BIT {
#define lowbit(i) ((i)&-(i))
	int c[N];

	void Build() {
		FOR(i,1,n) {
			c[i]+=len[i];
			if(i+lowbit(i)<=n)c[i+lowbit(i)]+=c[i];
		}
	}

	void Plus(int x,int d) { if(x>0)for(; x<=n; x+=lowbit(x))c[x]+=d; }

	int Sum(int x) {
		int ans(0);
		if(x>0)for(; x; x&=x-1)ans+=c[x];
		return ans;
	}

	int Binary(int k=(n>>1)+1) {
		int ans(0),sum(0);
		DOR(i,L,0)if((ans|1<<i)<=n&&sum+c[ans|1<<i]<k)sum+=c[ans|=1<<i];
		return ans+(sum<k);
	}
} bit;

namespace Sub {
	int Cmain() {
		/*DE("Init");*/
		//pos
		FOR(i,1,n)pos[a[i]]=i;
		pos[n+1]=n+1;
		//left
		int it(1);
		FOR(i,2,n>>1)if(a[i]>a[it])len[a[it]]=i-it,it=i;
		len[a[it]]=(n>>1)-it+1;
		//right
		it=(n>>1)+1;
		FOR(i,(n>>1)+2,n)if(a[i]>a[it])len[a[it]]=i-it,it=i;
		len[a[it]]=n-it+1;
		//nxt
		set<int> st;
		DOR(i,n,1) {
			nxt[a[i]]=(st.upper_bound(a[i])==st.end()?n+1:*st.upper_bound(a[i])),st.insert(a[i]);
			while(!st.empty()&&*st.begin()<a[i])st.erase(st.begin());
		}
		//bit
		bit.Build();
		/*DE("Solve");*/
		FOR(i,1,n) {
			for(const Pii &p:vec[i]) {
				int x(p.Fi),pla(bit.Binary(x));
				if(pla>1)x-=bit.Sum(pla-1);
				ans[p.Se]=a[pos[pla]+x-1];
			}
			if(flag)continue;
			int pla(bit.Binary()),sum(pla>1?bit.Sum(pla-1):0);
			if(sum==(n>>1)&&(flag==true))continue;
			for(int p(a[pos[pla]+(n>>1)-sum]); p&&p<=n&&pos[p]<pos[pla]+len[pla]; p=nxt[p])
				bit.Plus(p,len[p]=min(pos[pla]+len[pla],pos[nxt[p]])-pos[p]);
			int tmp(len[pla]);
			bit.Plus(pla,(len[pla]=(n>>1)-sum)-tmp);
		}
		/*DE("Output");*/
		FOR(i,1,Q)O(ans[i],'\n');
		return 0;
	}
}

signed main() {
#ifdef Plus_Cat
	freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
	I(n,Q),L=__lg(n);
	FOR(i,1,n)I(a[i]);
	FOR(i,1,Q) {
		int t,x;
		I(t,x),t?vec[min(n,t)].push_back({x,i}),0:ans[i]=a[x];
	}
	return Sub::Cmain();
}

posted @ 2025-05-26 19:51  Add_Catalyst  阅读(8)  评论(0)    收藏  举报