分析:这题就是求区间第k小数,但是这题和poj2104的区别就是,2104的区间是可以完全包含的,就是说某个点进出区间不止一次,所以平衡树和线段树是超时的,只能用划分树或者归并树,这题是可以用平衡树解的。先把区间从左到右排序,然后依次插入平衡树,线段树,然后利用树的性质在log n 内找到第k小。这题也可以用树状数组解,但是需要二分第k小,我一直觉得二分不是最好的做法,考虑能不能在log n内用树状数组找到第k小,一直做不到,所以这题没用树状数组写。
再说一下,平衡树中,treap最好写,sbt据说最快,而且附加域是有用的,是树的节点个数size,而伸展树很灵活可以快速合并分裂翻转,可以实现其他平衡树做不到的。
个人认为,必须要学会伸展树,然后SBT和treap一定要会一种。我学的是SBT。
然后,线段树需要先对数据二分+离散化,因为可能出现很大的值,很浪费内存。
因为要对区间排序,所以要保存区间的顺序下标,最后输出答案有两种方法,一种是获得解后重新按照区间出现顺序排序,第二种是直接ans[interval[i].index]=interval[i].k;
下面是三种不同的解法,线段树,SBT,伸展树。
最后,因为这一题开始只用了线段树写的,后面两种写法是后来学平衡树的时候写的,所以在判断区间重叠的时候不一样。后面多考虑了区间完全重叠的情况,这个数据是没有的,只是为了对拍数据用的。可以删掉。
线段树:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100005
#define M 50005
int n,m;
int pretty[N];
int dog[N];
struct inter{
int l,r,k;
int ans;
int index;
}interval[M];
struct tree{
int l,r,p;
}tree[N<<2];
int binary(int key)
{
int l=1,r=n;
while(l<=r){
int mid=(l+r)>>1;
if(pretty[mid]==key) return mid;
else if(key<pretty[mid]) r=mid-1;
else l=mid+1;
}
}
void build(int rt,int l,int r)
{
tree[rt].l=l;tree[rt].r=r;
if(l<r){
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
}
}
void insert(int rt,int i,int d)
{
tree[rt].p+=d;
if(tree[rt].l!=tree[rt].r){
int mid=(tree[rt].l+tree[rt].r)>>1;
if(mid>=i) insert(rt<<1,i,d);
else insert(rt<<1|1,i,d);
}
}
inline bool cmp(const inter &a, const inter &b)
{
return a.l<b.l||(a.l==b.l&&a.r<b.r);
}
inline bool operator<(const inter &a, const inter &b)
{
return a.index<b.index;
}
int query(int rt,int k)
{
if(tree[rt].l==tree[rt].r) return pretty[tree[rt].l];
if(tree[rt<<1].p>=k) return query(rt<<1,k);
else return query(rt<<1|1,k-tree[rt<<1].p);
}
int main()
{
memset(tree,0,sizeof(tree));
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++){
scanf("%d",pretty+i);
dog[i]=pretty[i];
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&interval[i].l,&interval[i].r,&interval[i].k);
interval[i].index=i;
}
sort(pretty+1,pretty+n+1);
sort(interval+1,interval+m+1,cmp);
for(int i=1;i<=n;i++)
dog[i]=binary(dog[i]);
build(1,1,n);
for(int i=interval[1].l;i<=interval[1].r;i++)
insert(1,dog[i],1);
interval[1].ans=query(1,interval[1].k);
for(int i=2;i<=m;i++){
if(interval[i].l<=interval[i-1].r){
for(int j=interval[i-1].l;j<interval[i].l;j++)
insert(1,dog[j],-1);
for(int j=interval[i-1].r+1;j<=interval[i].r;j++)
insert(1,dog[j],1);
}else{
for(int j=interval[i-1].l;j<=interval[i-1].r;j++)
insert(1,dog[j],-1);
for(int j=interval[i].l;j<=interval[i].r;j++)
insert(1,dog[j],1);
}
interval[i].ans=query(1,interval[i].k);
}
sort(interval+1,interval+m+1);
for(int i=1;i<=m;i++)
printf("%d\n",interval[i].ans);
return 0;
}
SBT:
#include<cstdio>
#include<algorithm>
const int maxn = 100009;
const int maxm = 50009;
struct cnode{
cnode *lchild,*rchild;
int s,key;
}node[maxn];
int sz=1;
inline cnode *newnode(cnode*l,cnode*r,int s,int key){
node[sz].lchild=l;
node[sz].rchild=r;
node[sz].s=s;
node[sz].key=key;
return node+sz++;
}
struct SBT{
cnode *root;
cnode *null;
SBT(){
root=null=node;
node[0].s=0;node[0].key=-1;
null->lchild=null->rchild=null;
}
~SBT(){
root=null=NULL;
}
void rotate_r(cnode*&t){
cnode *temp=t->lchild;
t->lchild=temp->rchild;
temp->rchild=t;
temp->s=t->s;
t->s=t->lchild->s+t->rchild->s+1;
t=temp;
}
void rotate_l(cnode*&t){
cnode *temp=t->rchild;
t->rchild=temp->lchild;
temp->lchild=t;
temp->s=t->s;
t->s=t->lchild->s+t->rchild->s+1;
t=temp;
}
void maintain(cnode*&t,bool type){
if(t==null)return;
if(!type){
if(t->lchild->lchild->s > t->rchild->s){
rotate_r(t);
}else if(t->lchild->rchild->s > t->rchild->s){
rotate_l(t->lchild);
rotate_r(t);
}else return;
}else{
if(t->rchild->rchild->s > t->lchild->s){
rotate_l(t);
}else if(t->rchild->lchild->s > t->lchild->s){
rotate_r(t->rchild);
rotate_l(t);
}else return;
}
maintain(t->lchild,false); maintain(t->rchild,true);
maintain(t,false);maintain(t,true);
}
void insert(cnode*&t,int key){
if(t==null){
t=newnode(null,null,1,key);
return;
}
t->s++;
if(key < t->key) insert(t->lchild,key);
else insert(t->rchild,key);
maintain(t,key>=root->key);
}
void erase(cnode*&t,int key){
if(t==null) return;
t->s--;
if(t->key==key){
if(t->lchild!=null&&t->rchild==null){
t=t->lchild;
}else if( t->lchild==null && t->rchild==null){
t=null;
}else{
cnode*temp=t->rchild;
while(temp->lchild!=null){temp=temp->lchild;}
t->key=temp->key;erase(t->rchild,temp->key);
}
}else if(key<t->key){
erase(t->lchild,key);
}else{
erase(t->rchild,key);
}
}
int kth(int k){
// printf("s: %d",root->s);
// travel();
cnode *t=root;
while(1){
if(t->lchild->s==k-1)return t->key;
else if(t->lchild->s > k-1){
t=t->lchild;
}else{
k-=1+t->lchild->s;
t=t->rchild;
}
}
}
void erase(int key){
erase(root,key);
}
void insert(int key){
insert(root,key);
}
void travel(){
travel(root);
}
void travel(cnode *t){
if(t!=null){
travel(t->lchild);
printf("%d %d\n",t->s,t->key);
travel(t->rchild);
}
}
};
SBT tree;
struct A{
int l,r,k,i;
}interval[maxn];
int a[maxn];
bool cmp2(const A&a,const A&b){
return a.l<b.l||a.l==b.l&&a.r<b.r;
}
bool cmp(const A&a,const A&b){
return a.i<b.i;
}
int main(){
int m,n;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
}
for(int i=0;i<m;i++){scanf("%d %d %d",&interval[i].l,&interval[i].r,&interval[i].k);interval[i].i=i;}
std::sort(interval,interval+m,cmp2);
int r=interval[0].r,l=interval[0].l;
for(int i=l;i<=r;i++) tree.insert(a[i]);
interval[0].k=tree.kth(interval[0].k);
for(int i=1;i<m;i++){
int R=interval[i].r,L=interval[i].l;
if(L>r){
while(l<=r){
tree.erase(a[l++]);
}
l=L;r=R;
while(L<=R){
tree.insert(a[L++]);
}
}else if(R>r){
while(l<L){
tree.erase(a[l++]);
}
while(++r<=R){
tree.insert(a[r]);
}
--r;
}
else{
while(l<L){
tree.erase(a[l++]);
}
while(r>R){
tree.erase(a[r--]);
}
}
interval[i].k=tree.kth(interval[i].k);
}
std::sort(interval,interval+m,cmp);
for(int i=0;i<m;i++)
printf("%d\n",interval[i].k);
return 0;
}
Splay:
#include<cstdio>
#include<algorithm>
const int INF = (unsigned(~0))>>1;
const int maxm = 50009;
const int maxn = 100009;
struct splaytree{
int sz;
struct node{
int s,v;
node *parent;
node *child[2];
};
node pool[maxn];
node* null;
node* root;
node nil;
splaytree(){
root=null=&nil;
nil.parent=nil.child[0]=nil.child[1]=null;
sz=nil.v=nil.s=0;
insert(-INF);
insert(INF);
}
node* newnode(node*p,int key){
pool[sz].parent=p;
pool[sz].child[0]=pool[sz].child[1]=null;
pool[sz].s=1;
pool[sz].v=key;
return pool+sz++;
}
void update(node* x){
if(x != null){
x->s = x->child[0]->s + x->child[1]->s + 1;
}
}
void insert(int key){
if(root==null){
root=newnode(null,key);
}else{
node *t=root;
while(true){
int d=t->v < key;
t->s++;
if(t->child[d]==null){
t->child[d] = newnode(t,key);
splay(t->child[d],null);
return;
}else{
t=t->child[d];
}
}
}
}
void remove(int value){
int k=find(value);
findkth(k-1,null);
findkth(k+1,root);
root->s--;
root->child[1]->s--;
root->child[1]->child[0]=null;
}
void rotate(node *x,int dr){
node *p = x->parent;
x->child[dr]->parent=p;
p->child[1^dr] = x->child[dr];
x->parent=p->parent;
x->child[dr]=p;
if(p->parent->child[0]==p){
p->parent->child[0]=x;
}else if(p->parent->child[1]==p){
p->parent->child[1]=x;
}else root=x;
p->parent=x;
update(p);
update(x);
}
void splay(node *x, node *y){
while(x->parent != y){
if(x->parent->parent==y){
if(x->parent->child[0]==x)rotate(x,1);
else rotate(x,0);
}else if(x->parent->parent->child[0] == x->parent){
if(x->parent->child[0]==x){
rotate(x->parent,1);
rotate(x,1);
}else{
rotate(x,0);
rotate(x,1);
}
}else{
if(x->parent->child[1]==x){
rotate(x->parent,0);
rotate(x,0);
}else{
rotate(x,1);
rotate(x,0);
}
}
}
}
int find(int key){
node *t=root;
int sum=0;
while(true){
if(t->v == key){
return sum + t->child[0]->s + 1;
}else if(t->v > key){
t = t->child[0];
}else{
sum += t->child[0]->s + 1;
t = t->child[1];
}
}
}
int getkth(int k){
findkth(k+1,null);
return root->v;
}
void findkth(int k,node *y){
node *x = root;
while(k != x->child[0]->s + 1){
if(k < x->child[0]->s + 1 ){
x = x->child[0];
}else{
k -= x->child[0]->s + 1;
x = x->child[1];
}
}
splay(x,y);
}
};
splaytree tree;
struct A{
int l,r,i,k;
}interval[maxn];
int a[maxn];
int ans[maxm];
bool operator<(const A&a,const A&b){
return a.l<b.l||a.l==b.l&&a.r<b.r;
}
int main(){
int m,n;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
}
for(int i=0;i<m;i++){scanf("%d %d %d",&interval[i].l,&interval[i].r,&interval[i].k);interval[i].i=i;}
std::sort(interval,interval+m);
int r=interval[0].r,l=interval[0].l;
for(int i=l;i<=r;i++) tree.insert(a[i]);
ans[interval[0].i]=tree.getkth(interval[0].k);
for(int i=1;i<m;i++){
int R=interval[i].r,L=interval[i].l;
if(L>r){
while(l<=r){
tree.remove(a[l++]);
}
l=L;r=R;
while(L<=R){
tree.insert(a[L++]);
}
}else if(R>r){
while(l<L){
tree.remove(a[l++]);
}
while(++r<=R){
tree.insert(a[r]);
}
--r;
}
else{
while(l<L){
tree.remove(a[l++]);
}
while(r>R){
tree.remove(a[r--]);
}
}
ans[interval[i].i]=tree.getkth(interval[i].k);
}
for(int i=0;i<m;i++)
printf("%d\n",ans[i]);
return 0;
}