【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继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。

Input

  第一行有两个正整数
  分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n]。
  接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。
  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。

Output

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

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

  m,n≤10000 , 0≤ai≤1e9。

Main idea

  询问区间中第k小的数是多少,需要支持单点修改点的权值。

Source

  我们看到这道题,发现对于一个询问应该是可以二分查找答案的,那么我们从整体二分的角度来思考。

  我们发现,如果没有修改的话,显然很简单,直接整体二分将所有询问一起操作即可。

  但是我们有操作,那应该怎么办呢?

  我们对于每一次修改,记录一下原来的值,简单来说,就是对于每一次操作,记录一下若opt=1,则表示这个点在这个状态的值;若opt=3,则表示这是一个询问

  我们对于修改来说,新增一个opt=2表示在修改之前的值。也就是说,我们在执行一个区间的操作时,如果发现一个opt=2,那么之前一定有一个一样的值的opt为1,并且其已经对答案造成影响,现在那个元素已经被修改了,就要相应地减去它之前对答案的影响,这样就完成了修改。

  然后我们整体二分权值,像静态查询kth那样修改一下即可。思路一气呵成 \(≧▽≦)/

Code

  1 #include<iostream>
  2 #include<string>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cmath>
  8 #include<map>
  9 using namespace std;
 10
 11 const int ONE=30005;
 12 const int INF=1e9+1;
 13
 14 int n,m;
 15 int x,y,k;
 16 char ch[3];
 17 int cnt,Num;
 18 int a[ONE],record[ONE];
 19 int Ans[ONE];
 20
 21 struct power
 22 {
 23         int opt,cnt;
 24         int l,r,k;
 25         int pos,value;
 26         int cur;
 27 }oper[ONE],qL[ONE],qR[ONE];
 28
 29 int get()
 30 {
 31         int res=1,Q=1;char c;
 32         while( (c=getchar())<48 || c>57 )
 33         if(c==‘-‘)Q=-1;
 34         res=c-48;
 35         while( (c=getchar())>=48 && c<=57 )
 36         res=res*10+c-48;
 37         return res*Q;
 38 }
 39
 40 namespace Bit
 41 {
 42         struct power
 43         {
 44             int value;
 45         }Node[ONE];
 46
 47         int lowbit(int i)
 48         {
 49             return i&-i;
 50         }
 51
 52         void Update(int R,int x)
 53         {
 54             for(int i=R;i<=n;i+=lowbit(i))
 55                 Node[i].value+=x;
 56         }
 57
 58         int Query(int R)
 59         {
 60             int res=0;
 61             for(int i=R;i>=1;i-=lowbit(i))
 62                 res+=Node[i].value;
 63             return res;
 64         }
 65 }
 66
 67 void Solve(int l,int r,int L,int R)
 68 {
 69         if(l>r) return;
 70         if(L==R)
 71         {
 72             for(int i=l;i<=r;i++)
 73             if(oper[i].opt==3)
 74                 Ans[oper[i].cnt] = L;
 75             return;
 76         }
 77
 78         int M=(L+R)>>1;
 79         for(int i=l;i<=r;i++)
 80         {
 81             if(oper[i].opt==1 && oper[i].value<=M)
 82                 Bit::Update(oper[i].pos,1);
 83             if(oper[i].opt==2 && oper[i].value<=M)
 84                 Bit::Update(oper[i].pos,-1);
 85             if(oper[i].opt==3)
 86                 record[i]=Bit::Query(oper[i].r) - Bit::Query(oper[i].l-1);
 87         }
 88
 89         for(int i=l;i<=r;i++)
 90         {
 91             if(oper[i].opt==1 && oper[i].value<=M)
 92                 Bit::Update(oper[i].pos,-1);
 93             if(oper[i].opt==2 && oper[i].value<=M)
 94                 Bit::Update(oper[i].pos,1);
 95         }
 96
 97         int l_num=0,r_num=0;
 98         for(int i=l;i<=r;i++)
 99         {
100             if(oper[i].opt!=3)
101             {
102                 if(oper[i].value <= M)
103                     qL[++l_num]=oper[i];
104                 else
105                     qR[++r_num]=oper[i];
106             }
107             else
108             {
109                 if(oper[i].cur + record[i] >= oper[i].k)
110                     qL[++l_num]=oper[i];
111                 else
112                 {
113                     qR[++r_num]=oper[i];
114                     qR[r_num].cur+=record[i];
115                 }
116             }
117         }
118
119         int t=l;
120         for(int i=1;i<=l_num;i++) oper[t++]=qL[i];
121         for(int i=1;i<=r_num;i++) oper[t++]=qR[i];
122
123
124         Solve(l,l+l_num-1,L,M);
125         Solve(l+l_num,r,M+1,R);
126 }
127
128 int main()
129 {
130         n=get();    m=get();
131         for(int i=1;i<=n;i++)
132         {
133             a[i]=get();
134             oper[++cnt].opt=1;    oper[cnt].pos=i;    oper[cnt].value=a[i];
135         }
136
137         for(int i=1;i<=m;i++)
138         {
139             scanf("%s",ch);
140             if(ch[0]==‘Q‘)
141             {
142                 x=get();    y=get();    k=get();
143                 oper[++cnt].opt=3;    oper[cnt].l=x;    oper[cnt].r=y;    oper[cnt].k=k;
144                 oper[cnt].cnt=++Num;
145             }
146             else
147             {
148                 x=get();    y=get();
149                 oper[++cnt].opt=2;    oper[cnt].pos=x;    oper[cnt].value=a[x];
150                 oper[++cnt].opt=1;    oper[cnt].pos=x;    oper[cnt].value=y;
151                 a[x]=y;
152             }
153         }
154
155         Solve(1,cnt,0,INF);
156
157         for(int i=1;i<=Num;i++)
158         printf("%d\n",Ans[i]);
159 }

时间: 2024-10-04 20:38:30

【BZOJ1901】Dynamic Rankings [整体二分]的相关文章

ZOJ 1112 Dynamic Rankings【动态区间第K大,整体二分】

题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112 题意: 求动态区间第K大. 分析: 把修改操作看成删除与增加,对所有操作进行整体二分. 代码: #include<cstdio> #include<iostream> #include<cstring> using namespace std; #define pr(x) cout << #x << &quo

[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】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

ZOJ 2112 Dynamic Rankings(带修改的区间第K大,分块+二分搜索+二分答案)

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)

题目链接:没有权限,进不去,题目也没法交,代码也不知道对不对,有好心人有权限帮忙交下吧QAQ 题目大意:带区间修改的第K小数 题目思路:有树套树,块状链表等优秀数据结构可以解决该题,当然我还是继续练习整体二分. 把修改操作拆开成两个操作 1.删除节点上的数 2.加入一个新数,然后更新的时候注意删除操作对树状数组的更新与插入操作相反,其他的没有难度 #include <iostream> #include <cstdio> #include <cstdlib> #incl

【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,树状数组套主席树

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

整体二分QAQ

POJ 2104 K-th Number 时空隧道 题意: 给出一个序列,每次查询区间第k小 分析: 整体二分入门题? 代码: 1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 //by NeighThorn 6 #define inf 0x3f3f3f3f 7 using namespace std; 8 9 const int maxn=

ZJU 2112 Dynamic Rankings

Dynamic Rankings Time Limit: 10000ms Memory Limit: 32768KB This problem will be judged on ZJU. Original ID: 211264-bit integer IO format: %lld      Java class name: Main The Company Dynamic Rankings has developed a new kind of computer that is no lon