题意:链接
方法:可持久化线段树。
解析:
可持久化数据结构好神啊,感觉都好玄妙的感觉。
首先建树的目的就是建立一棵权值树,维护的是在L,R里某些权值的数的出现个数。然后呢,对于1~n每个节点建一棵树,并且是基于前一棵树的基础上的。然后对于每一次的新值我们只需要update一次,并且连接一下原来的树?
神犇们不是说这种结构就是一堆线段树连啊连就出来了吗。
查询的时候呢?有一些小改变,据说是以二分为基础的查询。
神犇们发明这种数据结构的时候,就发现了这种数据结构里的所有线段树是可以相减的这种性质,于是,我们就可以二分答案在左边还是右边,递归搞下去最终的l就是目标值。
感觉要真正的理解还需要时间?我认为我现在就是理解个大概吧。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 500010
using namespace std;
struct node
{
int lson,rson,sum;
}seg[N*20];
int size;
int root[N];
void update(int p,int &q,int l,int r,int v)
{
seg[++size]=seg[p],q=size;
seg[q].sum++;
if(l==r)return ;
int mid=(l+r)>>1;
if(v<=mid)update(seg[p].lson,seg[q].lson,l,mid,v);
else update(seg[p].rson,seg[q].rson,mid+1,r,v);
}
int que(int L,int R,int l,int r,int k)
{
if(l==r)return l;
int mid=(l+r)>>1;
if(seg[seg[R].lson].sum-seg[seg[L].lson].sum>k)
{
return que(seg[L].lson,seg[R].lson,l,mid,k);
}
if(seg[seg[R].rson].sum-seg[seg[L].rson].sum>k)
{
return que(seg[L].rson,seg[R].rson,mid+1,r,k);
}
return 0;
}
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
update(root[i-1],root[i],1,n,x);
}
for(int i=1;i<=m;i++)
{
int L,R;
scanf("%d%d",&L,&R);
printf("%d\n",que(root[L-1],root[R],1,n,(R-L+1)>>1));
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-08 11:17:54