题解 区间第 k 小

传送门

考虑树套树
外层线段树对颜色开,在上面跑线段树二分
内层线段树对序列下标开,存外层线段树节点所包含的颜色在序列上的所有出现位置
然后在内层线段树上扫描线

  • 关于形如「出现次数 \(\leqslant w\) 的数的出现次数之和」或给它再带个权的限制:
    一个常见处理方式是扫描线,从右到左前 \(w\) 个权值为 1,第 \(w+1\) 个权值为 \(-w\)

那么把扫描线的过程可持久化下来即可
因为内存访问极其不连续的原因常数极大
大到完全几乎完全没法过的程度
复杂度 \(O(n\log^2 n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, w, q, typ;
int a[N];
#define ls(p) tree[p].lson
#define rs(p) tree[p].rson
#define sum(p) tree[p].sum

// namespace force{
// 	int sta[N], cnt[N], top;
// 	void solve() {
// 		for (int i=1,l,r,k,lst=0; i<=q; ++i) {
// 			l=read()^(lst*typ); r=read()^(lst*typ); k=read()^(lst*typ); top=0;
// 			for (int j=0; j<=n; ++j) cnt[j]=0;
// 			for (int j=l; j<=r; ++j) ++cnt[a[j]];
// 			for (int j=l; j<=r; ++j)
// 				if (cnt[a[j]]<=w) sta[++top]=a[j];
// 				else sta[++top]=n;
// 			sort(sta+1, sta+top+1);
// 			printf("%d\n", lst=sta[k]);
// 		}
// 	}
// }

// namespace task1{
// 	int *rot, *lson, *rson, *cnt, tot;
// 	void upd(int& p1, int p2, int tl, int tr, int pos, int val) {
// 		p1=++tot; ls(p1)=ls(p2); rs(p1)=rs(p2);
// 		if (tl==tr) {cnt[p1]=cnt[p2]+val; return ;}
// 		int mid=(tl+tr)>>1;
// 		if (pos<=mid) upd(ls(p1), ls(p2), tl, mid, pos, val);
// 		else upd(rs(p1), rs(p2), mid+1, tr, pos, val);
// 		cnt[p1]=cnt[ls(p1)]+cnt[rs(p1)];
// 	}
// 	int kth(int p1, int p2, int tl, int tr, int k) {
// 		if (tl==tr) return tl;
// 		int mid=(tl+tr)>>1, tem=cnt[ls(p2)]-cnt[ls(p1)];
// 		if (k<=tem) return kth(ls(p1), ls(p2), tl, mid, k);
// 		else return kth(rs(p1), rs(p2), mid+1, tr, k-tem);
// 	}
// 	void solve() {
// 		rot=new int[N]; cnt=new int[50*N];
// 		lson=new int[50*N]; rson=new int[50*N];
// 		memset(rot, 0, sizeof(int)*N);
// 		memset(cnt, 0, sizeof(int)*50*N);
// 		memset(lson, 0, sizeof(int)*50*N);
// 		memset(rson, 0, sizeof(int)*50*N);
// 		for (int i=1; i<=n; ++i) upd(rot[i], rot[i-1], 0, n, a[i], 1);
// 		for (int i=1,l,r,k,lst=0; i<=q; ++i) {
// 			l=read()^(lst*typ); r=read()^(lst*typ); k=read()^(lst*typ);
// 			printf("%d\n", lst=kth(rot[l-1], rot[r], 0, n, k));
// 		}
// 	}
// }

// namespace task2{
// 	vector<int> s;
// 	int **pre, *siz, *rot, *lson, *rson, *cnt, tot;
// 	void upd(int& p1, int p2, int tl, int tr, int pos, int val) {
// 		p1=++tot; ls(p1)=ls(p2); rs(p1)=rs(p2);
// 		if (tl==tr) {cnt[p1]=cnt[p2]+val; return ;}
// 		int mid=(tl+tr)>>1;
// 		if (pos<=mid) upd(ls(p1), ls(p2), tl, mid, pos, val);
// 		else upd(rs(p1), rs(p2), mid+1, tr, pos, val);
// 		cnt[p1]=cnt[ls(p1)]+cnt[rs(p1)];
// 	}
// 	int kth(int p1, int p2, int tl, int tr, int k) {
// 		if (tl==tr) return tl;
// 		int mid=(tl+tr)>>1, tem=cnt[ls(p2)]-cnt[ls(p1)];
// 		if (k<=tem) return kth(ls(p1), ls(p2), tl, mid, k);
// 		else return kth(rs(p1), rs(p2), mid+1, tr, k-tem);
// 	}
// 	void upd(int p, int tl, int tr, int pos, int val) {
// 		if (tl==tr) {cnt[p]+=val; return ;}
// 		int mid=(tl+tr)>>1;
// 		if (pos<=mid) upd(ls(p), tl, mid, pos, val);
// 		else upd(rs(p), mid+1, tr, pos, val);
// 		cnt[p]=cnt[ls(p)]+cnt[rs(p)];
// 	}
// 	void solve() {
// 		siz=new int[N];
// 		rot=new int[N]; cnt=new int[50*N];
// 		lson=new int[50*N]; rson=new int[50*N];
// 		memset(siz, 0, sizeof(int)*N);
// 		memset(rot, 0, sizeof(int)*N);
// 		memset(cnt, 0, sizeof(int)*50*N);
// 		memset(lson, 0, sizeof(int)*50*N);
// 		memset(rson, 0, sizeof(int)*50*N);
// 		for (int i=1; i<=n; ++i) upd(rot[i], rot[i-1], 0, n, a[i], 1), ++siz[a[i]];
// 		for (int i=0; i<n; ++i) if (siz[i]>w) s.pb(i);
// 		pre=new int*[s.size()+10];
// 		for (int i=0; i<s.size(); ++i) {
// 			pre[i]=new int[n+10];
// 			memset(pre[i], 0, sizeof(int)*(n+10));
// 			for (int j=1; j<=n; ++j) if (a[j]==s[i]) ++pre[i][j];
// 			for (int j=1; j<=n; ++j) pre[i][j]+=pre[i][j-1];
// 		}
// 		for (int i=1,l,r,k,lst=0; i<=q; ++i) {
// 			l=read()^(lst*typ); r=read()^(lst*typ); k=read()^(lst*typ);
// 			int all=r-l+1;
// 			for (int j=0; j<s.size(); ++j) if (pre[j][r]-pre[j][l-1]>w) {
// 				all-=pre[j][r]-pre[j][l-1];
// 				upd(rot[r], 0, n, s[j], pre[j][l-1]-pre[j][r]);
// 			}
// 			if (all<k) printf("%d\n", lst=n);
// 			else printf("%d\n", lst=kth(rot[l-1], rot[r], 0, n, k));
// 			for (int j=0; j<s.size(); ++j) if (pre[j][r]-pre[j][l-1]>w)
// 				upd(rot[r], 0, n, s[j], pre[j][r]-pre[j][l-1]);
// 		}
// 	}
// }

// namespace task3{
// 	int lst[N], rot[N], buc[N], del[N];
// 	namespace in{
// 		int rot[N*200], lson[N*200], rson[N*200], cnt[N*200], tot;
// 		void upd(int& p1, int p2, int tl, int tr, int pos, int val) {
// 			p1=++tot; ls(p1)=ls(p2); rs(p1)=rs(p2);
// 			if (tl==tr) {cnt[p1]=cnt[p2]+val; return ;}
// 			int mid=(tl+tr)>>1;
// 			if (pos<=mid) upd(ls(p1), ls(p2), tl, mid, pos, val);
// 			else upd(rs(p1), rs(p2), mid+1, tr, pos, val);
// 			cnt[p1]=cnt[ls(p1)]+cnt[rs(p1)];
// 		}
// 		int query(int p, int tl, int tr, int ql, int qr) {
// 			if (ql<=tl&&qr>=tr) return cnt[p];
// 			int mid=(tl+tr)>>1, ans=0;
// 			if (ql<=mid) ans+=query(ls(p), tl, mid, ql, qr);
// 			else ans+=query(rs(p), mid+1, tr, ql, qr);
// 			return ans;
// 		}
// 		int qcnt(int p, int l, int r) {return query(p, 0, n, l, r);}
// 	}
// 	namespace out{
// 		int rot[N*200], lson[N*200], rson[N*200], cnt[N*200], dat[N*200], tot, itst;
// 		void upd(int& p1, int p2, int tl, int tr, int col, int pos, int val) {
// 			p1=++tot; ls(p1)=ls(p2); rs(p1)=rs(p2);
// 			in::upd(dat[p1], dat[p2], 0, n, pos, val);
// 			if (tl==tr) return ;
// 			int mid=(tl+tr)>>1;
// 			if (col<=mid) upd(ls(p1), ls(p2), tl, mid, col, pos, val);
// 			else upd(rs(p1), rs(p2), mid+1, tr, col, pos, val);
// 		}
// 		int kth(int p1, int p2, int tl, int tr, int lim, int k) {
// 			// cout<<"kth: "<<tl<<' '<<tr<<' '<<lim<<' '<<k<<endl;
// 			if (tl==tr) return tl;
// 			int mid=(tl+tr)>>1, tem=in::qcnt(dat[ls(p2)], 0, lim)-in::qcnt(dat[ls(p1)], 0, lim);
// 			// cout<<"mid: "<<mid<<endl;
// 			// cout<<"tem: "<<tem<<endl;
// 			if (k<=tem) return kth(ls(p1), rs(p2), tl, mid, lim, k);
// 			else return kth(rs(p1), rs(p2), mid+1, tr, lim, k-tem);
// 		}
// 		int upd(int col, int pos, int val) {
// 			++itst;
// 			upd(rot[itst], rot[itst-1], 0, n, col, pos, val);
// 			return itst;
// 		}
// 		int qcnt(int id, int lim) {
// 			if (!lim) return 0;
// 			--lim;
// 			return in::qcnt(dat[rot[id]], 0, lim);
// 		}
// 		int kth(int idl, int idr, int l, int k) {
// 			--l;
// 			return kth(rot[idl], rot[idr], 0, n, l, k);
// 		}
// 	}
// 	void solve() {
// 		for (int i=1; i<=n; ++i) {
// 			if (lst[a[i]]) out::upd(a[i], del[lst[a[i]]], -1);
// 			rot[i]=out::upd(a[i], lst[a[i]], 1);
// 			del[i]=lst[a[i]];
// 			lst[a[i]]=i;
// 		}
// 		for (int i=1,l,r,k,lst=0; i<=q; ++i) {
// 			l=read()^(lst*typ); r=read()^(lst*typ); k=read()^(lst*typ);
// 			if (out::qcnt(rot[r], l)-out::qcnt(rot[l-1], l)<k) printf("%d\n", lst=n);
// 			else printf("%d\n", lst=out::kth(rot[l-1], rot[r], l, k));
// 		}
// 	}
// }

namespace task{
	bool vis[N];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	int sta[N], tot, top;
	pair<int, int> sta2[N];
	struct tr{int lson, rson, sum;}tree[N*500];
	int **que[N<<2], *now[N<<2], *dat[N<<2], *rot[N<<2];
	int tl[N<<2], tr[N<<2], siz[N<<2], vsiz[N<<2], cnt[N];
	#define pushup(p) sum(p)=sum(ls(p))+sum(rs(p))
	void upd(int& p1, int p2, int tl, int tr, int pos, int val) {
		sta[++top]=p1=++tot;
		while (1) {
			ls(p1)=ls(p2); rs(p1)=rs(p2);
			if (tl==tr) {sum(p1)=sum(p2)+val; break;}
			int mid=(tl+tr)>>1;
			if (pos<=mid) ls(p1)=sta[++top]=++tot, p1=tot, p2=ls(p2), tr=mid;
			else rs(p1)=sta[++top]=++tot, p1=tot, p2=rs(p2), tl=mid+1;
		}
		for (--top; top; --top) pushup(sta[top]);
		p1=sta[1];
	}
	int query(int p, int tl, int tr, int ql, int qr) {
		int ans=0, mid;
		sta[++top]=p; sta2[top]={tl, tr}; vis[top]=0;
		while (top) {
			p=sta[top]; tl=sta2[top].fir; tr=sta2[top].sec;
			if (ql<=tl&&qr>=tr) {--top; ans+=sum(p); continue;}
			mid=(tl+tr)>>1;
			if (!vis[top]&&ql<=mid&&ls(p)) {
				vis[top]=1;
				sta[++top]=ls(p); sta2[top]={tl, mid}; vis[top]=0;
				continue;
			}
			--top;
			if (qr>mid&&rs(p))
				sta[++top]=rs(p), sta2[top]={mid+1, tr}, vis[top]=0;
		}
		return ans;
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r;
		now[p]=new int[r-l+1]-l;
		que[p]=new int*[r-l+1]-l;
		for (int i=l; i<=r; ++i) now[p][i]=0;
		for (int i=l; i<=r; ++i) que[p][i]=new int[cnt[i]+1];
		if (l==r) {
			siz[p]=cnt[l];
			dat[p]=new int[siz[p]+1];
			rot[p]=new int[siz[p]+1];
			dat[p][0]=rot[p][0]=0;
			return ;
		}
		int mid=(l+r)>>1;
		if (l<=mid) build(p<<1, l, mid);
		if (r>mid) build(p<<1|1, mid+1, r);
		siz[p]=siz[p<<1]+siz[p<<1|1];
		dat[p]=new int[siz[p]+1];
		rot[p]=new int[siz[p]+1];
		dat[p][0]=rot[p][0]=0;
	}
	void upd(int p, int pos, int val) {
		int tem;
		dat[p][++vsiz[p]]=val;
		que[p][pos][++now[p][pos]]=vsiz[p];
		upd(tem, rot[p][vsiz[p]-1], 1, siz[p], vsiz[p], 1);
		if (now[p][pos]>=w+2)
			upd(tem, tem, 1, siz[p], que[p][pos][now[p][pos]-w-1], w);
		if (now[p][pos]>=w+1)
			upd(tem, tem, 1, siz[p], que[p][pos][now[p][pos]-w], -w-1);
		rot[p][vsiz[p]]=tem;
		if (tl(p)==tr(p)) return ;
		int mid=(tl(p)+tr(p))>>1;
		if (pos<=mid) upd(p<<1, pos, val);
		else upd(p<<1|1, pos, val);
	}
	int qcnt(int p, int l, int r, int k) {
		int id=upper_bound(dat[p], dat[p]+vsiz[p]+1, r)-dat[p]-1;
		l=lower_bound(dat[p], dat[p]+vsiz[p]+1, l)-dat[p];
		return query(rot[p][id], 1, siz[p], l, id);
	}
	int kth(int p, int l, int r, int k) {
		// cout<<"kth: "<<tl(p)<<' '<<tr(p)<<' '<<k<<endl;
		if (tl(p)==tr(p)) return tl(p);
		int tem=qcnt(p<<1, l, r, k);
		// cout<<"mid: "<<((tl(p)+tr(p))>>1)<<endl;
		// cout<<"tem: "<<tem<<endl;
		if (k<=tem) return kth(p<<1, l, r, k);
		else return kth(p<<1|1, l, r, k-tem);
	}
	void solve() {
		for (int i=1; i<=n; ++i) ++cnt[a[i]];
		build(1, 0, n);
		for (int i=1; i<=n; ++i) upd(1, a[i], i);
		for (int i=1,l,r,k,lst=0; i<=q; ++i) {
			l=read()^(lst*typ); r=read()^(lst*typ); k=read()^(lst*typ);
			printf("%d\n", lst=kth(1, l, r, k));
		}
		// cout<<"tot: "<<tot<<endl;
	}
}

signed main()
{
	freopen("kth.in", "r", stdin);
	freopen("kth.out", "w", stdout);

	n=read(); w=read(); q=read(); typ=read();
	for (int i=1; i<=n; ++i) a[i]=read();
	// force::solve();
	// if (w==n) task1::solve();
	// else task2::solve();
	// task3::solve();
	task::solve();

	return 0;
}
posted @ 2022-06-16 07:20  Administrator-09  阅读(3)  评论(0编辑  收藏  举报