码迷,mamicode.com
首页 > 编程语言 > 详细

zoj 2112 Dynamic Rankings(树状数组套主席树)

时间:2015-08-18 18:46:25      阅读:185      评论:0      收藏:0      [点我收藏+]

标签:

题意:对于一段区间,每次求[l,r]的第k大,存在单点修改操作;

思路:

       学习主席树参考:

http://blog.csdn.net/wjf_wzzc/article/details/24560117(各种形式)

http://blog.csdn.net/bossup/article/details/31921235(推荐)

http://blog.csdn.net/xiaofengcanyuexj/article/details/25553521?utm_source=tuicool(图解)

http://blog.csdn.net/metalseed/article/details/8045038(原理)

--------------------------------------------

主席树是一种可持久化的线段树,支持历史版本查询,区间不同数的个数查询,区间第k大查询等动态操作;

由很多棵线段树组成的树,每棵子树记录包含数字的个数,相当于维护不同的区间;单独线段树无法求不同区间的第k大,而主席树可以;

开始时先建一棵空树,作为原始版本;每次更新(插入一个数)时都尽量利用历史版本,即节省空间,又提高了效率;并采用了二分的思想;

询问时,通过二分枚举最优值,与两端点对应的树的左子树的差值(即为该数在[l,r]中的个数)比较,分治到左右区间中查询;

---------------------------------------------

本题使用树状数组维护动态树的前缀和,降低复杂度,查询时再将数在动态树与静态树中出现次数并起来一起比较;

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=60010;
const int M=2500010;
int n,q,m,tot;
int a[maxn],t[maxn];
int T[maxn],lson[M],rson[M],c[M];
int S[maxn];
int used[maxn];
struct node{
  int kind;
  int l,r,k;
}query[10010];
void Init_hash(int k)
{
    sort(t,t+k);
    m=unique(t,t+k)-t;
}
int hash(int x)
{
    return lower_bound(t,t+m,x)-t;
}
int build(int l,int r){
   int root=tot++;
   c[root]=0;
   if(l!=r){
      int mid=(l+r)/2;
      lson[root]=build(l,mid);
      rson[root]=build(mid+1,r);
   }
   return root;
}
int Insert(int root,int pos,int val)
{
    int newroot=tot++,tmp=newroot;
    int l=0,r=m-1;
    c[newroot]=c[root]+val;
    while(l<r)
    {
        int mid=(l+r)/2;
        if(pos<=mid){
            lson[newroot]=tot++;rson[newroot]=rson[root];
            newroot=lson[newroot];root=lson[root];
            r=mid;
        }
        else{
            rson[newroot]=tot++;lson[newroot]=lson[root];
            newroot=rson[newroot];root=rson[root];
            l=mid+1;
        }
        c[newroot]=c[root]+val;
    }
    return tmp;
}
int lowbit(int x){
   return x&(-x);
}
/*void add(int x,int pos,int val){
   while(x<=n){
      S[x]=Insert(S[x],pos,val);
      x+=lowbit(x);
   }
}*/
int sum(int x){
  int ret=0;
  while(x>0){
    ret+=c[lson[used[x]]];
    x-=lowbit(x);
  }
  return ret;
}
int Query(int left,int right,int k){
   int left_root=T[left-1];
   int right_root=T[right];
   int l=0,r=m-1;
   for(int i=left-1;i;i-=lowbit(i)) used[i]=S[i];
   for(int i=right;i;i-=lowbit(i)) used[i]=S[i];
   while(l<r){
     int mid=(l+r)/2;
     int tmp=sum(right)-sum(left-1)+c[lson[right_root]]-c[lson[left_root]];
     if(tmp>=k){
        r=mid;
        for(int i=left-1;i;i-=lowbit(i)) used[i]=lson[used[i]];
        for(int i=right;i;i-=lowbit(i)) used[i]=lson[used[i]];
        left_root=lson[left_root];
        right_root=lson[right_root];
     }
     else{
        l=mid+1;
        k-=tmp;
        for(int i=left-1;i;i-=lowbit(i)) used[i]=rson[used[i]];
        for(int i=right;i;i-=lowbit(i)) used[i]=rson[used[i]];
        left_root=rson[left_root];
        right_root=rson[right_root];
     }
   }
   return l;
}
void modify(int x,int p,int d){
    while(x<=n){
        S[x]=Insert(S[x],p,d);
        x+=lowbit(x);
    }
}
int main()
{
    int Tcase;
    scanf("%d",&Tcase);
    while(Tcase--){
        scanf("%d%d",&n,&q);
        tot=0;
        m=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            t[m++]=a[i];
        }
        char op[10];
        for(int i=0;i<q;i++){
            scanf("%s",op);
            if(op[0]==Q){
                query[i].kind=0;
                scanf("%d%d%d",&query[i].l,&query[i].r,&query[i].k);
            }
            else{
                query[i].kind=1;
                scanf("%d%d",&query[i].l,&query[i].r);
                t[m++]=query[i].r;
            }
        }
        Init_hash(m); //离散化,使树的数量尽量小
        T[0]=build(0,m-1); //建一棵树,有编号,但节点数量为0
        for(int i=1;i<=n;i++) T[i]=Insert(T[i-1],hash(a[i]),1);
        for(int i=1;i<=n;i++) S[i]=T[0];
        for(int i=0;i<q;i++){
            if(query[i].kind==0){
                printf("%d\n",t[Query(query[i].l,query[i].r,query[i].k)]);
            }
            else{
                modify(query[i].l,hash(a[query[i].l]),-1);
                modify(query[i].l,hash(query[i].r),1);
                a[query[i].l]=query[i].r;
            }
        }
    }
    return 0;
}

 

zoj 2112 Dynamic Rankings(树状数组套主席树)

标签:

原文地址:http://www.cnblogs.com/dominatingdashuzhilin/p/4740139.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!