倍增法和ST算法 个人学习笔记代码
倍增法
P4155 国旗计划
#include<bits/stdc++.h>
#define endl '\n'
#define forr(i,l,r) for(int i=l;i<=r;i++)
#define reforr(i,l,r) for(int i=r;i>=l;i--)
#define int long long
using namespace std;
const int N=4e5+10,M=20;
struct wa
{int id,l,r;
}a[N*2];
int n,m,nt;
int go[N][M],res[N];
void init(){int nxt=1;forr(i,1,nt){while (nxt<=nt&&a[nxt].l<=a[i].r)//找下一个最优区间{nxt++;}go[i][0]=nxt-1;//2^0=1 记录跳一步的最优位置}//递推for(int i=1;(1<<i)<=n;i++){//倍增forr(s,1,nt){go[s][i]=go[go[s][i-1]][i-1];//跳到2^(i-1)的跳板 再跳2^(i-1)}}
}
void fans(int x){int len=a[x].l+m;//绕一圈int ans=0,cur=x;reforr(i,0,(int)log2(N)){//从最大数开始跳int pos=go[cur][i];if(pos&&a[pos].l<len){ans+=(1<<i);cur=pos;//跳到新位置}}res[a[x].id]=ans+1;//排过序 不是以前的顺序了 输出答案要还原顺序
}
void solve()
{cin>>n>>m;forr(i,1,n){a[i].id=i;cin>>a[i].l>>a[i].r;if(a[i].r<a[i].l)a[i].r+=m;}sort(a+1,a+n+1,[](wa x,wa y){return x.l<y.l;});nt=n;forr(i,1,n){nt++,a[nt].l=a[i].l+m,a[nt].r=a[i].r+m;//拆环成链}init();forr(i,1,n) fans(i);forr(i,1,n)cout<<res[i]<<' ';}
signed main()
{ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);int t=1;// cin>>t;while(t--) solve();return 0;
}
ST算法
用于求解静态数组RMQ(区间最值查询)问题
P2880 Balanced Lineup G
const int N=5e4+10,M=20;
int n,m;
int a[N],l2[N];
int dpmn[N][M],dpmx[N][M];
void init(){l2[0]=-1;//log2递推计算forr(i,1,N)l2[i]=l2[i>>1]+1;forr(i,1,n){//初始化dpmx[i][0]=a[i];dpmn[i][0]=a[i];}int p=log2(n);//递推forr(i,1,p){//区间长度 小区间凑出大区间for(int s=1;s+(1<<i)<=n+1;s++){//左端点位置dpmx[s][i]=max(dpmx[s][i-1],dpmx[s+(1<<(i-1))][i-1]);dpmn[s][i]=min(dpmn[s][i-1],dpmn[s+(1<<(i-1))][i-1]);}}
}
int ans(int l,int r){int k=l2[r-l+1];//2^k<=len 2^(k+1)>=len int mx=max(dpmx[l][k],dpmx[r-(1<<k)+1][k]);int mn=min(dpmn[l][k],dpmn[r-(1<<k)+1][k]);return mx-mn;
}
void solve()
{cin>>n>>m;forr(i,1,n){cin>>a[i];}init();forr(i,1,m){int l,r;cin>>l>>r;cout<<ans(l,r)<<endl;}
}