整体二分:
对于一类要求支持离线操作和询问达成某条件的操作次数的问题,可以把所有询问扔到一起二分答案。
具体地,每次对于操作区间$[l,r]$,将位于$[l,mid]$之间的操作做掉,然后依次判断答案位于$[l,r]$之间的每个询问的条件达没达成。
如果达成则该询问的答案$leq mid$,扔到操作区间$[l,mid]$;否则该询问的答案$>mid$,扔到操作区间$[mid+1,r]$。
如果$l=r$则更新这些询问的答案,否则清空操作并继续递归左右两边的操作区间。
复杂度$O(nlog{n} imes 操作复杂度)$。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define maxn 300005 #define maxm 500005 #define inf 0x7fffffff #define ll unsigned long long #define rint register ll #define debug(x) cerr<<#x<<": "<<x<<endl #define fgx cerr<<"--------------"<<endl #define dgx cerr<<"=============="<<endl using namespace std; ll P[maxn],L[maxn],R[maxn],n,m; ll C[maxn<<1],A[maxn],ans[maxn]; vector<ll> nd[maxn],pos[maxn]; ll tp1[maxn],tp2[maxn]; inline ll read(){ ll x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline ll lowbit(ll x){return x&(-x);} inline void add(ll x,ll y){for(ll i=x;i<=2*m;i+=lowbit(i))C[i]+=y;} inline ll qry(ll x){ll res=0;for(ll i=x;i;i-=lowbit(i))res+=C[i];return res;} inline void solve(ll l,ll r){ ll mid=l+r>>1,tot1=0,tot2=0; for(rint i=l;i<=mid;i++) add(L[i],A[i]),add(R[i]+1,-A[i]); for(rint i=0;i<nd[l].size();i++){ rint u=nd[l][i],res=0; for(rint j=0;j<pos[u].size();j++) res+=qry(pos[u][j]); if(l==r) (res>=P[u])?(ans[u]=l):(ans[u]=-1); else{ if(res>=P[u]) tp1[++tot1]=u; else P[u]-=res,tp2[++tot2]=u; } } nd[l].clear(); for(rint i=l;i<=mid;i++) add(L[i],-A[i]),add(R[i]+1,A[i]); if(l!=r){ for(rint i=1;i<=tot1;i++) nd[l].push_back(tp1[i]); for(rint i=1;i<=tot2;i++) nd[mid+1].push_back(tp2[i]); solve(l,mid),solve(mid+1,r); } } int main(){ n=read(),m=read(); for(rint i=1;i<=m;i++) {ll x=read();pos[x].push_back(i),pos[x].push_back(i+m);} for(rint i=1;i<=n;i++) P[i]=read(); ll k=read(); for(rint i=1;i<=k;i++){ L[i]=read(),R[i]=read(),A[i]=read(); if(R[i]<L[i]) R[i]+=m; } for(rint i=1;i<=n;i++) nd[1].push_back(i); solve(1,k); for(rint i=1;i<=n;i++){ if(ans[i]==-1) printf("NIE "); else printf("%lld ",ans[i]); } return 0; }
CDQ分治:
对于一类子区间之间会产生影响的分治问题,可以在归并时处理左边对右边的影响。
一般用来解三维偏序,大概是第一维$sort$,第二维归并,第三维数据结构来做。
复杂度$O(nlog{n} imes 操作复杂度)$。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #define maxn 100005 #define maxm 200005 #define inf 0x7fffffff #define ll long long using namespace std; int N,K,cnt,f[maxn],sum[maxm]; struct node{ int a,b,c,w,ans; }e[maxn],t[maxn],t1[maxn],t2[maxn],t3[maxn]; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline bool cmp(node x,node y){ if(x.a==y.a && x.b==y.b) return x.c<y.c; else if(x.a==y.a) return x.b<y.b; else return x.a<y.a; } inline int lowbit(int x){return x&-x;} inline int query(int x){int s=0; for(int i=x;i;i-=lowbit(i)) s+=sum[i];return s;} inline void add(int x,int y){for(int i=x;i<=K;i+=lowbit(i)) sum[i]+=y;} inline bool check(int i,int j){return t[i].a==t[j].a && t[i].b==t[j].b && t[i].c==t[j].c;} inline void cdq(int l,int r){ if(l==r) return; int mid=l+r>>1; cdq(l,mid),cdq(mid+1,r); int p0=0,p1=0,p2=0,p3=0; for(int i=l;i<=mid;i++) t1[++p1]=e[i]; for(int i=mid+1;i<=r;i++) t2[++p2]=e[i]; for(int i=1;i<=p2;i++){ while(t1[p0+1].b<=t2[i].b && p0<p1) t3[++p3]=t1[++p0],add(t3[p3].c,t3[p3].w); t3[++p3]=t2[i],t3[p3].ans+=query(t3[p3].c); } for(int i=p0+1;i<=p1;i++) t3[++p3]=t1[i]; for(int i=l;i<=r;i++) e[i]=t3[i-l+1]; for(int i=1;i<=p0;i++) add(t1[i].c,-t1[i].w); return; } int main(){ cnt=read(),K=read(); for(int i=1;i<=cnt;i++) t[i].a=read(),t[i].b=read(),t[i].c=read(); sort(t+1,t+1+cnt,cmp); for(int i=1;i<=cnt;){ e[++N]=t[i]; int j=i; while(check(i,j)&&j<=cnt) j++; e[N].w=j-i,i=j; } cdq(1,N); for(int i=1;i<=N;i++) f[e[i].ans+e[i].w-1]+=e[i].w; for(int i=0;i<cnt;i++) printf("%d ",f[i]); return 0; }
三分:
寻找单峰函数的极值。注意整数三分的下界是$r-l+1geq 4$。
复杂度$O(nlog{n})$。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> using namespace std; #define MAXN 100005 #define MAXM 500005 #define INF 0x7fffffff #define ll long long #define eps 1e-6 double A[MAXN];int N; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline double power(double a,int b){ double ans=1.0; while(b){ if(b&1) ans*=a; a*=a,b>>=1; }return ans; } inline double gety(double x){ double ans=0.0; for(int i=N;i>=0;i--) ans+=A[i]*power(x,i); return ans; } int main(){ N=read();double l,r; scanf("%lf%lf",&l,&r); for(int i=N;i>=0;i--) scanf("%lf",&A[i]); while(l+eps<=r){ //cout<<l<<" "<<r<<endl; double t1=l+((r-l)/3.0); double t2=r-((r-l)/3.0); if(gety(t1)>gety(t2)) r=t2; else l=t1; } printf("%.5lf ",l); return 0; }