整体二分

补算法。

一种基于离线处理某些序列可带修问题的算法,比方说区间动态第 \(k\) 大,实测下来常数是树套树的十分之一。

展开来说,我们的每一个询问都是一个可以二分的问题,暴力做法一般是 \(O(qn\log n)\),整体二分可以做到 \(O(q\log V \log n)\) 的优秀复杂度。

其主要思想就是,把所有询问和修改放入一个序列中,然后对序列和答案区间同时分治,比方说我们记当前处理的序列区间为 \([ql,qr]\),答案区间为 \([l,r]\),当 \(l=r\) 时,显然 \([ql,qr]\) 中所有询问的答案均为 \(l\),否则当 \(l \neq r\) 时将 \([ql,qr]\) 继续分类下去分治。

P2617 Dynamic Rankings

可离线区间动态第 \(k\) 大。
\(1 \leq n,q \leq 10^5,V \leq 10^9\)

我们可以把赋初值看做一次插入,一次修改看做一次删除和插入,将其与询问插入序列中,然后分治,每一次用树状数组将答案在 \([l,mid]\)\([mid+1,r]\) 的序列分隔开,大概与 cdq 的思想差不多,之后再继续递归,知道找到答案,代码很好写,跑的很快。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define pr putchar('\n')
#define fi first
#define se second
#define pp putchar(' ')
#define pii pair<ll,ll>
#define pdi pair<ll,ll>
#define mem(aa,bb) memset(aa,bb,sizeof(aa))
#define fo(a,i,b) for(register ll i = a ; i <= b ; ++ i )
#define Fo(a,i,b) for(register ll i = a ; i >= b ; -- i )
#define pb push_back
//#pragma GCC optimize(2)
using namespace std;
//typedef int ll;
typedef long long ll;
//typedef __int128 ll;
typedef double db;
inline void read(ll &opp){ll x=0,t=1;char ch;ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-'){t=-1;}ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}opp=x*t;return; }
inline void wr(ll x){if(x<0){putchar('-');x=-x;}if(x>9){wr(x/10);}putchar(x%10+'0');}
const ll N=1e6+5,M=2e4+5,mod=1e9+7;
ll n,a[N],m,cnt,num,ans[N],bit[N];
struct node{ll l,r,k,op,id;}Q[N],Q1[N],Q2[N];
#define lowbit(x) (x&(-x))
inline void upd(ll i,ll k){for(;i<=n;i+=lowbit(i)) bit[i]+=k;}
inline ll ask(ll i){if(!i) return 0;ll ans=0;for(;i;i-=lowbit(i)) ans+=bit[i];return ans;}
inline void solve(ll l,ll r,ll ql,ll qr)
{
	if(ql>qr) return;
	if(l==r)
	{
		fo(ql,i,qr) if(Q[i].op==2) ans[Q[i].id]=l;
		return;
	}
	ll mid=l+r>>1,c1=0,c2=0;
	fo(ql,i,qr)
	{
		if(Q[i].op==1)
			if(Q[i].l<=mid) Q1[++c1]=Q[i],upd(Q[i].id,Q[i].r);
			else Q2[++c2]=Q[i];
		else 
		{
			ll tmp=ask(Q[i].r)-ask(Q[i].l-1);
			if(Q[i].k<=tmp) Q1[++c1]=Q[i];
			else Q[i].k-=tmp,Q2[++c2]=Q[i];
		}
	}
	fo(1,i,c1) if(Q1[i].op==1) upd(Q1[i].id,-Q1[i].r);
	fo(1,i,c1) Q[ql+i-1]=Q1[i];
	fo(1,i,c2) Q[ql+c1+i-1]=Q2[i];
	solve(l,mid,ql,ql+c1-1);
	solve(mid+1,r,ql+c1,qr);
}
signed main(){
	read(n),read(m);fo(1,i,n) read(a[i]),Q[++cnt]={a[i],1,0,1,i};
	fo(1,i,m)
	{
		char c;cin>>c;ll x,y,k;read(x),read(y);
		if(c=='C') Q[++cnt]={a[x],-1,0,1,x},Q[++cnt]={a[x]=y,1,0,1,x}; 
		else read(k),Q[++cnt]={x,y,k,2,++num};
	}
	solve(-1e9,1e9,1,cnt);
	fo(1,i,num) wr(ans[i]),pr;
	return 0;
}
posted @ 2025-04-05 16:23  Wei_Han  阅读(31)  评论(0)    收藏  举报