带修莫队 + 权值线段树...
并不是很优秀的时间复杂度...在洛谷不开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;
}

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

被折叠的 条评论
为什么被折叠?



