「模板」 主席树/可持久化线段树/函数式线段树
我的理解就是建一堆不同的根,然后指向相同的点,或说是一堆不同的树共用着一部分点。
挺费空间的,但是思路很巧妙啊,而且可持久化是很重要的东西。
代码更新于 2018.06.27。
#include <algorithm>
#include <cstdio>
#include <cstring>
const int MAXN=200010;
int n, m, q;
class PersistableSegmentTree
{
private:
int value[MAXN];
struct Node
{
int v;
Node *c[2];
Node(int v):v(v)
{
c[0]=c[1]=nullptr;
}
Node(int l, int r)
{
c[0]=c[1]=nullptr;
if(l==r)
return;
int mid=l+r>>1;
c[0]=new Node(l, mid);
c[1]=new Node(mid+1, r);
}
~Node(void)
{
if(c[0]!=nullptr)
delete c[0];
if(c[1]!=nullptr)
delete c[1];
}
}*root[MAXN];
void Update(Node* &i, Node* j, int l, int r, int v)
{
i=new Node(j->v+1);
if(l==r)
{
i->v=j->v+1;
return;
}
int mid=l+r>>1;
memcpy(i->c, j->c, sizeof j->c);
if(v>mid)
Update(i->c[1], j->c[1], mid+1, r, v);
else
Update(i->c[0], j->c[0], l, mid, v);
}
int Find(Node* i, Node* j, int l, int r, int k)
{
if(l==r)
return value[l];
int mid=l+r>>1, v=j->c[0]->v-i->c[0]->v;
if(k>v)
return Find(i->c[1], j->c[1], mid+1, r, k-v);
else
return Find(i->c[0], j->c[0], l, mid, k);
}
public:
PersistableSegmentTree(int n)
{
int *a=new int[n+1];
std::fill(root, root+n+1, nullptr);
for(int i=1; i<=n; ++i)
{
scanf("%d", &a[i]);
value[i]=a[i];
}
std::sort(value+1, value+n+1);
m=std::unique(value+1, value+n+1)-value-1;
root[0]=new Node(1, m);
for(int i=1, pos; i<=n; ++i)
{
pos=std::lower_bound(value+1, value+m+1, a[i])-value;
Update(root[i], root[i-1], 1, m, pos);
}
delete []a;
}
void Find(int l, int r, int k)
{
printf("%d
", Find(root[l-1], root[r], 1, m, k));
}
}*T;
int main(int argc, char** argv)
{
scanf("%d %d", &n, &q);
T=new PersistableSegmentTree(n);
for(int i=1, l, r, k; i<=n; ++i)
{
scanf("%d %d %d", &l, &r, &k);
T->Find(l, r, k);
}
delete T;
return 0;
}
谢谢阅读。