zoj2112

题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112

经典的动态区间第K大。

用树状数组套线段树。

对原数组建一个树状数组,每个树状数组的结点代表一个线段树,这个线段树以权值为下标,包括这个树状数组的结点包含的区间。

插入的时候可以由树状数组和线段树写法类比,只与logn棵线段树有关,每棵线段树用时logn,总共的时间复杂度n*logn^2。

询问[l,r]的时候,类似与前缀和,找到与l-1有关的logn棵线段树,找到与人有关的logn棵线段树,然后类似于静态区间第K大,判断是往左子树还是右子树,有2logn棵线段树,判断往左子树还是右子树logn次,总共的时间复杂度n*logn^2。

网址上空间比较小,这个程序会MLE。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional>
#include<deque>
#include<cctype>
#include<climits>
#include<complex>
//#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj

using namespace std;

typedef long long LL;
typedef double DB;
typedef pair<int,int> PII;
typedef complex<DB> CP;

#define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define re(i,a,b)  for(i=a;i<=b;i++)
#define red(i,a,b) for(i=a;i>=b;i--)
#define fi first
#define se second
#define m_p(a,b) make_pair(a,b)
#define SF scanf
#define PF printf
#define two(k) (1<<(k))

template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}

const DB EPS=1e-9;
inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
const DB Pi=acos(-1.0);

inline int gint()
  {
        int res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==‘-‘){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
        return (neg)?-res:res;
    }
inline LL gll()
  {
      LL res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==‘-‘){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
        return (neg)?-res:res;
    }

const int maxN=50000;
const int maxM=10000;
const int maxcnt=maxN+maxM;

int N,M;
int a[maxN+100];
struct Tdata
  {
      char type;
      int l,r,k,t;
      inline void input()
        {
            type=getchar();while(!(type==‘C‘ || type==‘Q‘))type=getchar();
            if(type==‘Q‘){l=gint();r=gint();k=gint();}else{l=gint();t=gint();}
        }
    }data[maxM+100];

int bak[maxcnt+100],cnt;

struct Tnode{int son[2],val;}sn[maxcnt*100+10000];int idx;
int tree[maxN+100];

inline int newnode(){++idx;sn[idx].son[0]=sn[idx].son[1]=sn[idx].val=0;return idx;}
inline void update(int p,int l,int r,int x,int val)
  {
      while(1)
        {
            sn[p].val+=val;
            if(l==r)break;
            int mid=(l+r)/2;
            int f=(x>mid);
            if(!sn[p].son[f])sn[p].son[f]=newnode();
            if(x<=mid){p=sn[p].son[0];r=mid;}else{p=sn[p].son[1];l=mid+1;}
        }
  }

#define lowbit(a) (a&(-a))
inline void change(int a,int x,int val)
  {
      for(;a<=N;a+=lowbit(a))
          update(tree[a],1,cnt,x,val);
    }

int lge,larr[maxN+100],rge,rarr[maxN+100];
inline int ask(int l,int r,int k)
  {
      int i;
      l--;
      lge=0;
      for(;l>=1;l-=lowbit(l))larr[++lge]=tree[l];
      rge=0;
      for(;r>=1;r-=lowbit(r))rarr[++rge]=tree[r];
      int x=1,y=cnt;
      while(1)
        {
            if(x==y)return bak[x];
            int mid=(x+y)/2,G=0;
            re(i,1,rge)G+=sn[sn[rarr[i]].son[0]].val;
            re(i,1,lge)G-=sn[sn[larr[i]].son[0]].val;
            if(G<k)
              {
                  k-=G;
                  x=mid+1;
                  re(i,1,rge)rarr[i]=sn[rarr[i]].son[1];
                  re(i,1,lge)larr[i]=sn[larr[i]].son[1];
              }
            else
              {
                  y=mid;
                  re(i,1,rge)rarr[i]=sn[rarr[i]].son[0];
                  re(i,1,lge)larr[i]=sn[larr[i]].son[0];
              }
        }
  }

int main()
  {
      freopen("zoj2112.in","r",stdin);
      freopen("zoj2112.out","w",stdout);
      int i;
      for(int Case=gint();Case;Case--)
        {
            N=gint();M=gint();
            re(i,1,N)a[i]=gint();
            re(i,1,M)data[i].input();
            cnt=0;
            re(i,1,N)bak[++cnt]=a[i];
            re(i,1,M)if(data[i].type==‘C‘)bak[++cnt]=data[i].t;
            sort(bak+1,bak+cnt+1);
            cnt=unique(bak+1,bak+cnt+1)-bak-1;
            re(i,1,N)a[i]=lower_bound(bak+1,bak+cnt+1,a[i])-bak;
            re(i,1,M)if(data[i].type==‘C‘)data[i].t=lower_bound(bak+1,bak+cnt+1,data[i].t)-bak;
            idx=0;
            re(i,0,N)tree[i]=newnode();
            re(i,1,N)change(i,a[i],1);
            re(i,1,M)
              {
                  int x;
                  switch(data[i].type)
                    {
                        case ‘C‘:
                            x=data[i].l;
                            change(x,a[x],-1);
                            a[x]=data[i].t;
                            change(x,a[x],1);
                        break;
                        case ‘Q‘:
                            printf("%d\n",ask(data[i].l,data[i].r,data[i].k));
                        break;
                    }
              }
        }
      return 0;
  }

时间: 2024-10-06 20:46:44

zoj2112的相关文章

zoj2112 主席树动态第k大 (主席树&amp;&amp;树状数组)

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They

ZOJ2112 动态区间Kth(单点修改) 线段树+Treap写法

---恢复内容开始--- 题意:给出一个序列和操作次数, 每次操作修改一个位置的数 或者 询问一个区间第k小的数 分析:单点修改可以考虑线段树, 区间排名可以用平衡树 所以线段树+Treap 用一颗线段树将序列划分 每颗Treap中插入的是对应区间的数 在每个数加入时, 顺便将该数插入线段树中包含该位置的那些区间上的Treap即可 单点修改同理, 将所有包含要修改的位置的区间上的Treap都删去原数并插入新数 询问第k小的数:由于询问的区间不一定恰好对应某棵Treap, 不便直接求出名次, 但是

[bzoj1901][zoj2112][Dynamic Rankings]

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They

[主席树]ZOJ2112 Dynamic Rankings

题意:n个数,q个询问 (n<=50000, q<=10000) Q x y z 代表询问[x, y]区间里的第z小的数 C x y    代表将(从左往右数)第x个数变成y 上篇介绍了在[x, y]区间内查询第z小的数的方法(静态主席树) 本题有更新操作 若仍用上篇的做法, 每次更新一个数,需要更新的是T[i], T[i+1]... ...T[n](该数所在的树以及它后面的所有树) 因为每棵树T[i]所记录的都是前缀(1到i的数出现的次数) 因此,改变i,会影响i到n的所有树 这样,每次更新

zoj2112 主席树动态第k大 ( 参考资料链接)

参考链接: http://blog.csdn.net/acm_cxlove/article/details/8565309 http://www.cnblogs.com/Rlemon/archive/2013/05/24/3096264.html http://seter.is-programmer.com/posts/31907.html http://blog.csdn.net/metalseed/article/details/8045038

zoj2112 Dynamic Rankings 动态区间第k大,树状数组套平衡树

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int

可持久化数据结构之主席树

转自:http://finaltheory.info/?p=249 HomeACM可持久化数据结构之主席树 06十2013 可持久化数据结构之主席树 Written by FinalTheory on. Posted in ACM 引言 首先引入CLJ论文中的定义: 所谓的“持久化数据结构”,就是保存这个数据结构的所有历史版本,同时利用它们之间的共用数据减少时间和空间的消耗. 本文主要讨论两种可持久化线段树的算法思想.具体实现以及编码技巧. 核心思想 可持久化线段树是利用函数式编程的思想,对记录

zoj2112--Dynamic Rankings(树状数组+主席树)

题目连接:zoj2112 给出n个点,两种操作,Q:询问在[l,r]内的第k大的数,C:更改第i个数位x 动态的询问第k大,使用树状数组修改和查询前缀和. 因为给出的空间小,所以可以将n个点做成一个静态的主席树,然后对于修改的值,在另一个主席树中修改,查询时同时查询这两个主席树就可以了. #include <cstdio> #include <cstring> #include <algorithm> using namespace std ; #pragma comm

带修改的主席树

普通主席树认为是前缀套线段树,那么这就是树状数组套线段树 前缀区间由原来的一个前缀一个线段树变成BIT组成的几棵线段树一起 每个线段树维护的还是离散排序后的数列 每个节点也相当于一个主席树,我觉得更像是线段树,但是修改的时候用到了主席树的方法,就是在原来的基础上修改(只不过这些原来的都不保存) add操作要修改一些主席树 sum操作要加一些主席树的区间和 外层的BIT是为了处理询问区间,内层是为了找k值 kth时候要把用到的主席树提出了,每个都往左往右 代码(未提交过) // // main.c