1901: Zju2112 Dynamic Rankings

本文介绍了一种结合带修莫队算法和权值线段树的数据结构解决方案,通过调整修改操作来优化查询效率。适用于处理大量更新和查询请求,尤其是在离线查询场景中表现出较好的性能。

带修莫队 + 权值线段树...

并不是很优秀的时间复杂度...在洛谷不开O2过不了最后一个点...

很好理解的算法,就是在每次操作时调整修改操作,使得在当前 询问前的所有棋子已经被修改,以后都没更改

,然后把l,r对应到查询区间,查询第k小就好了,如果k不大于左子树下的数量,则答案在左子树,否则就在右子树,搞定...

c++代码如下:

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i = x; i <= y; ++ i)
#define repd(i,x,y) for(register int i = x; i >= y; -- i)
typedef long long ll;
using namespace std;
template<typename T>inline void read(T&x)
{
	x = 0;char c;int sign = 1;
	do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
	do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
	x *= sign;
}

const int N = 1e4 + 500,inf = 1e9+7;
int n,m,cnt1,cnt2,a[N],ans[N],belong[N];char c[2];
bool _is[N];
struct Que { int l,r,k,t; }q[N];
struct Upd { int p,x,t,lst; }t[N];
struct segment_tree
{
	int root,sz,ls[2000000],rs[2000000],val[2000000];
	
	void update(int&id,int l,int r,int p,int w)
	{
		if(!id) id = ++ sz;
		val[id] += w;
		if(l == r) return ;
		int mid = l + r >> 1;
		if(p <= mid) update(ls[id],l,mid,p,w);
		else update(rs[id],mid + 1,r,p,w); 
	}
	
	int find(int id,int l,int r,int k)
	{
		if(l == r) return l;
		int mid = l + r >> 1;
		if(k <= val[ls[id]] ) return find(ls[id],l,mid,k);
		else return find(rs[id],mid + 1,r,k - val[ls[id]]);
	}
}seg;

const bool cmp(Que a,Que b)
{
	if(belong[a.l] != belong[b.l]) return belong[a.l] < belong[b.l];
	if(belong[a.r] != belong[b.r]) return belong[a.r] < belong[b.r];
	return a.t < b.t;
}

int main()
{
	read(n);read(m);
	rep(i,1,n) read(a[i]),++a[i];
	rep(i,1,m)
	{
		scanf("%s",c);
		if(c[0] == 'Q')
		{
			read(q[++cnt1].l); read(q[cnt1].r);
			read(q[cnt1].k); q[cnt1].t = i;
		}
		else
		{
			read(t[++cnt2].p); read(t[cnt2].x);
			t[cnt2].t = i;_is[i] = 1; t[cnt2].x++;
		}
	}
	
	int d = max(1,(int)pow(n,2.0/3));
	rep(i,1,n)
		belong[i] = i/d+1;
	
	sort(q + 1,q + 1 + cnt1,cmp);
	
	int l = 1,r = 0,T = 0;t[cnt2+1].t = m + 1;
	rep(i,1,m)
	{
		while(t[T].t > q[i].t)
		{
			if(t[T].p <= r && t[T].p >= l)
			{
				seg.update(seg.root,1,inf,t[T].x,-1);
				seg.update(seg.root,1,inf,t[T].lst,1);
			}
			a[t[T].p] = t[T].lst;
			T--;
		}
		while(t[T + 1].t < q[i].t)
		{
			T++;
			if(t[T].p <= r && t[T].p >= l)
			{
				seg.update(seg.root,1,inf,t[T].x,1);
				seg.update(seg.root,1,inf,a[t[T].p],-1);
			}
			t[T].lst = a[t[T].p];
			a[t[T].p] = t[T].x;
		}
		
		while(l < q[i].l)
		{
			seg.update(seg.root,1,inf,a[l],-1);
			++l;
		}
		while(l > q[i].l)
		{
			--l;
			seg.update(seg.root,1,inf,a[l],1);
		}
		while(r < q[i].r)
		{
			++r;
			seg.update(seg.root,1,inf,a[r],1);
		}
		while(r > q[i].r)
		{
			seg.update(seg.root,1,inf,a[r],-1);
			--r;
		}
		ans[q[i].t] = seg.find(seg.root,1,inf,q[i].k);
	}
	
	rep(i,1,m) if(!_is[i]) printf("%d\n",ans[i] - 1);
	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值