【BZOJ1901】Dynamic Rankings

Description

给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。

Input

对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。

Output

输出文件应包含T行。对于每一组数据,如果该关卡有解,输出一行Yes;否则输出一行No。

Sample Input

5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3

Sample Output

3
6

HINT

20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。

【分析】

裸的主席树,直接上模板就行了。

  1 /**************************************************************
  2     Problem: 1901
  3     User: TCtower
  4     Language: C++
  5     Result: Accepted
  6     Time:612 ms
  7     Memory:24988 kb
  8 ****************************************************************/
  9
 10 #include <iostream>
 11 #include <cstring>
 12 #include <cstdio>
 13 #include <cmath>
 14 #include <cstring>
 15 #include <algorithm>
 16 #include <vector>
 17 //#define LOCAL
 18 const int maxn=10000+5;
 19 const int INF=99999999;
 20 const int maxnode=2000000+10;
 21 using namespace std;
 22 struct OP
 23 {
 24        int type;//0代表询问,1代表改变
 25        int l,r,k;
 26 }op[maxn];
 27 //点结构体
 28 struct node
 29 {
 30        int ls,rs,w;
 31        node(){ls=rs=w=0;}
 32 }T[maxnode];
 33 vector<int>LX;
 34 vector<int>Q1,Q2;
 35 int a[maxn],n,q,n1;
 36 int cnt,root[maxn*2];
 37
 38 void init();
 39 void work();
 40 //树状数组用
 41 inline int lowbit(int i){return i&-i;}
 42 inline int find(int i)
 43 {
 44        //二分查找不解释
 45        return (lower_bound(LX.begin(),LX.begin()+n1,i)-LX.begin())+1;
 46 }
 47 void build(int &i,int l,int r,int val);
 48 void query(int l,int r,int k);//区间第k大
 49 //其实我觉得不传副本速度会上升?
 50 int Qy(vector<int>Q1,vector<int>Q2,int l,int r,int k);
 51 void my_ins(int pos,int x,int v);
 52 void ins(int &i,int l,int r,int x,int v);
 53
 54 int main()
 55 {
 56     #ifdef LOCAL
 57     freopen("data.txt","r",stdin);
 58     freopen("out.txt","w",stdout);
 59     #endif
 60     init();//读入与初始化
 61     work();
 62     return 0;
 63 }
 64 void init()
 65 {
 66     scanf("%d%d",&n,&q);
 67     LX.clear();
 68     for (int i=1;i<=n;i++)
 69     {
 70         scanf("%d",&a[i]);
 71         LX.push_back(a[i]);
 72     }
 73     char str[10];
 74     for (int i=1;i<=q;i++)
 75     {
 76         scanf("%s",str);
 77         if (str[0]==‘Q‘)
 78         {
 79             op[i].type=0;
 80             scanf("%d%d%d",&op[i].l,&op[i].r,&op[i].k);
 81         }
 82         else
 83         {
 84             op[i].type=1;
 85             scanf("%d%d",&op[i].l,&op[i].r);
 86             LX.push_back(op[i].r);
 87         }
 88     }
 89     sort(LX.begin(),LX.end());
 90     n1=unique(LX.begin(),LX.end())-LX.begin();
 91 }
 92 void ins(int &i,int l,int r,int x,int v)
 93 {
 94      if (i==0) {T[++cnt]=T[i];i=cnt;}//没有创建过新的节点
 95      T[i].w+=v;
 96      if (l==r) return;
 97      int mid=(l+r)>>1;
 98      if (x<=mid) ins(T[i].ls,l,mid,x,v);
 99      else ins(T[i].rs,mid+1,r,x,v);
100 }
101 void my_ins(int pos,int x,int v)
102 {
103      int t=find(x);//找到x的位置
104      for (int i=pos;i<=n;i+=lowbit(i))
105      {
106          ins(root[i],1,n1,t,v);
107      }
108 }
109 int Qy(vector<int>Q1,vector<int>Q2,int l,int r,int k)
110 {
111     if (l==r) return l;
112     int c=0,mid=(l+r)>>1;
113     //这两句可以互换,统计总数
114     for (int i=0;i<Q1.size();i++) c-=T[T[Q1[i]].ls].w;
115     for (int i=0;i<Q2.size();i++) c+=T[T[Q2[i]].ls].w;
116     //大于k说明在左子树中而不右子树
117     for (int i=0;i<Q1.size();i++) Q1[i]=(c>=k?T[Q1[i]].ls:T[Q1[i]].rs);
118     for (int i=0;i<Q2.size();i++) Q2[i]=(c>=k?T[Q2[i]].ls:T[Q2[i]].rs);
119     if (c>=k) return Qy(Q1,Q2,l,mid,k);//继续向下寻找
120     else return Qy(Q1,Q2,mid+1,r,k-c);
121 }
122 void query(int l,int r,int k)
123 {
124      Q1.clear();Q2.clear();//临时队列清空
125      Q1.push_back(root[l!=1?l-1+n:0]);
126      Q2.push_back(root[r+n]);
127      for (int i=l-1;i;i-=lowbit(i)) Q1.push_back(root[i]);
128      for (int i=r;i;i-=lowbit(i)) Q2.push_back(root[i]);
129      int t=Qy(Q1,Q2,1,n1,k);
130      printf("%d\n",LX[t-1]);
131 }
132 void work()
133 {
134      cnt=0;
135      memset(root,0,sizeof(root));
136      for (int i=1;i<=n;i++)
137      {
138          root[i+n]=root[i+n-1];
139          int t=find(a[i]);
140          build(root[i+n],1,n1,t);
141      }
142      for (int i=1;i<=q;i++)
143      {
144          if (op[i].type==0)
145          query(op[i].l,op[i].r,op[i].k);
146          else
147          {
148               my_ins(op[i].l,a[op[i].l],-1);
149               my_ins(op[i].l,op[i].r,1);
150               //修改
151               a[op[i].l]=op[i].r;
152          }
153      }
154 }
155 void build(int &i,int l,int r,int val)
156 {
157      //对于修改过的每一个点
158      //都要新建一个副本
159      T[++cnt]=T[i];i=cnt;
160      T[i].w++;
161      if (l==r) return;
162      int mid=(l+r)>>1;
163      //按值建线段树
164      if (val<=mid) build(T[i].ls,l,mid,val);
165      else build(T[i].rs,mid+1,r,val);
166 }

【BZOJ1901】Dynamic Rankings

时间: 2024-11-08 08:36:07

【BZOJ1901】Dynamic Rankings的相关文章

【BZOJ-1901】Dynamic Rankings 带修主席树

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 7292  Solved: 3038[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i

【BZOJ1901】Dynamic Rankings [整体二分]

Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题.你需要编一个这样的程序

【BZOJ1901】Dynamic Rankings,树状数组套主席树

Time:2016.05.09 Author:xiaoyimi 转载注明出处谢谢 传送门(权限) 题面 1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MB Submit: 6678 Solved: 2777 [Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a

【BZOJ】【1901】【Zju2112】 Dynamic Rankings

再填个坑. 动态维护区间第K大(带单点修改) 首先裸的区间第K大我们是用的[前缀和]思想,实现O(n)预处理,O(1)找树查询,那么如果是动态的呢?我们可以利用树状数组(BIT)的思想,进行O(logn)的修改,O(logn)的查询(当然由于是在线段树上做,都各需要再乘logn的复杂度) 也就是说,每次修改,一块改logn棵线段树:每次查询也是在logn棵线段树上一起往下找! 1 //BZOJ 1901 2 #include<cstdio> 3 #include<cstring>

[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

BZOJ1901 Zju2112 Dynamic Rankings 【树状数组套主席树】

题目 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改 变后的a继续回答上面的问题. 输入格式 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000). 分别表示序列的长度和指令的个数. 第二行有n个数,表示a[1],a[2]--a[n],这些数都小于10^9. 接下来的m

【树状数组套权值线段树】bzoj1901 Zju2112 Dynamic Rankings

谁再管这玩意叫树状数组套主席树我跟谁急 明明就是树状数组的每个结点维护一棵动态开结点的权值线段树而已 好吧,其实只有一个指针,指向该结点的权值线段树的当前结点 每次查询之前,要让指针指向根结点 不同结点的权值线段树之间毫无关联 可以看这个:http://blog.csdn.net/popoqqq/article/details/40108669?utm_source=tuicool #include<cstdio> #include<algorithm> using namespa

【分块】bzoj1901 Zju2112 Dynamic Rankings

区间k大,分块大法好,每个区间内存储一个有序表. 二分答案,统计在区间内小于二分到的答案的值的个数,在每个整块内二分.零散的暴力即可. 还是说∵有二分操作,∴每个块的大小定为sqrt(n*log2(n))比较快呢. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 int n,a[10001],num[

【分块】【权值分块】bzoj1901 Zju2112 Dynamic Rankings

论某O(n*sqrt(n))的带修改区间k大值算法. 首先对序列分块,分成sqrt(n)块. 然后对权值分块,共维护sqrt(n)个权值分块,对于权值分块T[i],存储了序列分块的前i块的权值情况. 对于区间询问,需要获得区间中每个值出现的次数,然后按权值扫O(sqrt(n)),完整的部分我们可以通过权值分块差分(O(1))得到(比如Lb~Rb块就是T[Rb]-T[Lb-1]),零散的部分我们再维护一个额外的权值分块,累计上该值即可.O(sqrt(n)). 对于修改,直接在该位置之后的所有权值分