【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
,程序必须回答这样的询问:对于给定的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
。
接下来的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 33 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
36
HINT
m,n≤10000 , 0≤ai≤1e9。
Main idea
询问区间中第k小的数是多少,需要支持单点修改点的权值。
Solution
我们看到这道题,发现对于一个询问应该是可以二分查找答案的,那么我们从整体二分的角度来思考。
我们发现,如果没有修改的话,显然很简单,直接整体二分将所有询问一起操作即可。
但是我们有操作,那应该怎么办呢?
我们对于每一次修改,记录一下原来的值,简单来说,就是对于每一次操作,记录一下若opt=1,则表示这个点在这个状态的值;若opt=3,则表示这是一个询问,
我们对于修改来说,新增一个opt=2,表示在修改之前的值。也就是说,我们在执行一个区间的操作时,如果发现一个opt=2,那么之前一定有一个一样的值的opt为1,并且其已经对答案造成影响,现在那个元素已经被修改了,就要相应地减去它之前对答案的影响,这样就完成了修改。
然后我们整体二分权值,像静态查询kth那样修改一下即可。思路一气呵成 \(≧▽≦)/
Code
#include<iostream> #include<string> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<map> using namespace std; const int ONE=30005; const int INF=1e9+1; int n,m; int x,y,k; char ch[3]; int cnt,Num; int a[ONE],record[ONE]; int Ans[ONE]; struct power { int opt,cnt; int l,r,k; int pos,value; int cur; }oper[ONE],qL[ONE],qR[ONE]; int get() { int res=1,Q=1;char c; while( (c=getchar())<48 || c>57 ) if(c=='-')Q=-1; res=c-48; while( (c=getchar())>=48 && c<=57 ) res=res*10+c-48; return res*Q; } namespace Bit { struct power { int value; }Node[ONE]; int lowbit(int i) { return i&-i; } void Update(int R,int x) { for(int i=R;i<=n;i+=lowbit(i)) Node[i].value+=x; } int Query(int R) { int res=0; for(int i=R;i>=1;i-=lowbit(i)) res+=Node[i].value; return res; } } void Solve(int l,int r,int L,int R) { if(l>r) return; if(L==R) { for(int i=l;i<=r;i++) if(oper[i].opt==3) Ans[oper[i].cnt] = L; return; } int M=(L+R)>>1; for(int i=l;i<=r;i++) { if(oper[i].opt==1 && oper[i].value<=M) Bit::Update(oper[i].pos,1); if(oper[i].opt==2 && oper[i].value<=M) Bit::Update(oper[i].pos,-1); if(oper[i].opt==3) record[i]=Bit::Query(oper[i].r) - Bit::Query(oper[i].l-1); } for(int i=l;i<=r;i++) { if(oper[i].opt==1 && oper[i].value<=M) Bit::Update(oper[i].pos,-1); if(oper[i].opt==2 && oper[i].value<=M) Bit::Update(oper[i].pos,1); } int l_num=0,r_num=0; for(int i=l;i<=r;i++) { if(oper[i].opt!=3) { if(oper[i].value <= M) qL[++l_num]=oper[i]; else qR[++r_num]=oper[i]; } else { if(oper[i].cur + record[i] >= oper[i].k) qL[++l_num]=oper[i]; else { qR[++r_num]=oper[i]; qR[r_num].cur+=record[i]; } } } int t=l; for(int i=1;i<=l_num;i++) oper[t++]=qL[i]; for(int i=1;i<=r_num;i++) oper[t++]=qR[i]; Solve(l,l+l_num-1,L,M); Solve(l+l_num,r,M+1,R); } int main() { n=get(); m=get(); for(int i=1;i<=n;i++) { a[i]=get(); oper[++cnt].opt=1; oper[cnt].pos=i; oper[cnt].value=a[i]; } for(int i=1;i<=m;i++) { scanf("%s",ch); if(ch[0]=='Q') { x=get(); y=get(); k=get(); oper[++cnt].opt=3; oper[cnt].l=x; oper[cnt].r=y; oper[cnt].k=k; oper[cnt].cnt=++Num; } else { x=get(); y=get(); oper[++cnt].opt=2; oper[cnt].pos=x; oper[cnt].value=a[x]; oper[++cnt].opt=1; oper[cnt].pos=x; oper[cnt].value=y; a[x]=y; } } Solve(1,cnt,0,INF); for(int i=1;i<=Num;i++) printf("%d\n",Ans[i]); }View Code
- BZOJ 1901 Zju2112 Dynamic Rankings ——整体二分
- 整体二分--BZOJ1901: Zju2112 Dynamic Rankings
- 【BZOJ】【P1901】【Zju2112 Dynamic Rankings】【题解】【整体二分】
- 【BZOJ1901】Zju2112 Dynamic Rankings【树状数组套主席树 / 整体二分】
- [bzoj1901][zoj2112][Dynamic Rankings] (整体二分+树状数组 or 动态开点线段树 or 主席树)
- 【bzoj1901】Dynamic Rankings(整体二分)
- 【bzoj3110】[Zjoi2013]K大数查询 整体二分+树状数组区间修改
- bzoj 3110 [Zjoi2013]K大数查询【树套树||整体二分】
- BZOJ 2738 矩阵乘法 整体二分+二维树状数组
- BZOJ.3110.[ZJOI2013]K大数查询(整体二分 树状数组/线段树)
- BZOJ3110 K大数查询 【线段树 + 整体二分 或 树套树(非正解)】
- BZOJ 2738: 矩阵乘法|分块|整体二分
- 【BZOJ】【P1146】【CTSC2008】【网络管理Network】【题解】【整体二分+dfs序+树状数组】
- BZOJ 2738 矩阵乘法(整体二分+二维树状数组)
- 【BZOJ2738】矩阵乘法【整体二分】
- BZOJ 2738 矩阵乘法 整体二分+二维树状数组
- bzoj 2527 [Poi2011]Meteors 整体二分+树状数组
- 【BZOJ2527】【POI2011】Meteors(整体二分)
- bzoj 4538: [Hnoi2016]网络 (整体二分+树状数组)
- 【BZOJ4009】接水果(整体二分,扫描线)