1. 程式人生 > >[Luogu2617]Dynamic Rankings(整體二分)

[Luogu2617]Dynamic Rankings(整體二分)

names getch 比較 oid query truct ans 進行 inline

Luogu

動態區間第K大的整體二分解法

之前學主席樹的時候就做了這道題(明明是樹套樹不是主席樹啊),碼量挺大而且調了我一個晚上。換成整體二分我半個小時就寫完了而且一A。
寫起來就是爽。
其實原理很簡單,先把修改和詢問放在一起,註意這裏不能排序,要嚴格按照時間戳進行處理。
區間的初值也視作一次修改,之後的每次修改要當成兩次,即刪除原先那個數,再加入新的那個數。
對於當前的一些詢問,二分一個答案\(mid\)。處理所有修改的值小於等於\(mid\)的修改操作,用樹狀數組維護區間內有多少個數的值小於等於\(mid\),再把這個數與詢問的\(k\)比較,選擇向左遞歸(答案更小)還是向右遞歸(答案更大)。註意向左向右的時候要保證原修改查詢的有序性,即對於某一個修改和某一個查詢,若他們被分在了相同的一邊(左或右),那麽他們的相對順序一定不能改變。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N = 1e5+5;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-'
) w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } struct node{ int opt,x,y,id,k; }q[N],q1[N],q2[N]; int n,m,cnt,qcnt,a[N],tmp[N],c[N],ans[N]; void modify(int k,int v){while (k<=n) c[k]+=v,k+=k&-k;} int
query(int k){int s=0;while (k) s+=c[k],k-=k&-k;return s;} 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 (q[i].opt==0) ans[q[i].id]=l; return; } int mid=l+r>>1; for (int i=L;i<=R;i++) if (q[i].opt==0) tmp[q[i].id]=query(q[i].y)-query(q[i].x-1); else if (q[i].y<=mid) modify(q[i].x,q[i].opt); for (int i=L;i<=R;i++) if (q[i].opt!=0&&q[i].y<=mid) modify(q[i].x,-q[i].opt); int t1=0,t2=0; for (int i=L;i<=R;i++) if (q[i].opt==0) if (q[i].k<=tmp[q[i].id]) q1[++t1]=q[i]; else q[i].k-=tmp[q[i].id],q2[++t2]=q[i]; else if (q[i].y<=mid) q1[++t1]=q[i]; else q2[++t2]=q[i]; for (int i=L,j=1;j<=t1;i++,j++) q[i]=q1[j]; for (int i=L+t1,j=1;j<=t2;i++,j++) q[i]=q2[j]; solve(L,L+t1-1,l,mid);solve(L+t1,R,mid+1,r); } int main() { n=gi();m=gi(); for (int i=1;i<=n;i++) { a[i]=gi(); q[++cnt]=(node){1,i,a[i]}; } for (int i=1;i<=m;i++) { char ch=getchar(); while (ch!='C'&&ch!='Q') ch=getchar(); if (ch=='C') { int x=gi(),y=gi(); q[++cnt]=(node){-1,x,a[x]}; a[x]=y; q[++cnt]=(node){1,x,a[x]}; } else { int l=gi(),r=gi(),k=gi(); q[++cnt]=(node){0,l,r,++qcnt,k}; } } solve(1,cnt,0,1e9); for (int i=1;i<=qcnt;i++) printf("%d\n",ans[i]); return 0; }

[Luogu2617]Dynamic Rankings(整體二分)