[LUOGU] P1081 开车旅行
终于告一段落了。
需要快速求出(logn级别)的量是每个点往后不超过x长度,A和B能开的长度和到达的点。
用f[i][j]表示点i开始,往后两人共开2^j次到达的点,A[i][j]和B[i][j]分别表示两人从i开始共开2^j次行驶的距离
然后用类似倍增求LCA的思路,由大往小逼近即可求出指定解。
对于问题1,需要n次logn的查询,对于问题2,需要m次logn的查询,总复杂度在O((n+m)logn)
问题是,如何求这个倍增数组?
先考虑求j=0时,我们要求出每个点的前驱和后继才能方便判断,就想到了建一颗平衡树,倒着加点,同时更新每个点的最近点和次近点(根据题目定义,向下靠拢)
这样就可以方便地倍增啦!
然而,题解中有更好的方法求前驱后继,待我研究一下..
是这样的,我们需要求前驱,后继,大概是两位的距离,而且可以离线,所以可以把原数组排序,用双向链表串起来,可以方便找前两个和后两个,也可以方便地删除..
预处理复杂度也是在O(nlogn)的
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<map> #define check(x) (x==ch[fa[x]][1]) #define clear(x) val[x]=cnt[x]=siz[x]=ch[x][0]=ch[x][1]=fa[x]=0 #define pushup(x) siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+cnt[x] #define R register int #define int long long using namespace std; const int MAXN=400005; const int INF=1ll<<50; int val[MAXN],cnt[MAXN],siz[MAXN]; int ch[MAXN][2],fa[MAXN]; int tot,root; inline int newnode(int x){cnt[++tot]++;siz[tot]=1;val[tot]=x;return tot;} void rotate(int x){ int y=fa[x],z=fa[fa[x]]; bool ck=check(x); fa[ch[x][ck^1]]=y;ch[y][ck]=ch[x][ck^1]; ch[x][ck^1]=y;fa[y]=x;fa[x]=z; if(z) ch[z][ch[z][1]==y]=x; pushup(y);pushup(x); } void splay(int x){ for(R f=fa[x];f;rotate(x),f=fa[x]) if(fa[f]) rotate(check(f)==check(x)?f:x); root=x; } void insert(int x){ if(!root){root=newnode(x);return;} int cur=root,f=0; while(1){ if(val[cur]==x){cnt[cur]++;pushup(cur);pushup(f);splay(cur);return;} f=cur;cur=ch[cur][x>val[cur]]; if(!cur){cur=newnode(x);fa[cur]=f;ch[f][x>val[f]]=cur;pushup(f);splay(cur);return;} } } int rk(int x){ int cur=root,ret=0; while(1){ if(x<val[cur]) cur=ch[cur][0]; else{ ret+=siz[ch[cur][0]]; if(val[cur]==x) return splay(cur),ret+1;// ret+=cnt[cur];cur=ch[cur][1]; } } } int kth(int x){ int cur=root; while(1){ if(ch[cur][0]&&x<=siz[ch[cur][0]]) cur=ch[cur][0]; else{ x-=siz[ch[cur][0]]+cnt[cur]; if(x<=0) return cur; cur=ch[cur][1]; } } } int prev(){ int cur=ch[root][0]; while(ch[cur][1]) cur=ch[cur][1]; return cur; } int nxtv(){ int cur=ch[root][1]; while(ch[cur][0]) cur=ch[cur][0]; return cur; } void del(int x){ rk(x); if(cnt[root]>1){cnt[root]--;pushup(root);return;} if(!ch[root][0]&&!ch[root][1]){clear(root);root=0;return;} if(!ch[root][0]){int sav=root;root=ch[sav][1];fa[root]=0;clear(sav);return;} if(!ch[root][1]){int sav=root;root=ch[sav][0];fa[root]=0;clear(sav);return;} int sav=root; splay(prev()); ch[root][1]=ch[sav][1]; fa[ch[sav][1]]=root; clear(sav); pushup(root); } int pre(int x){ insert(x);int ret=prev(); del(x);return val[ret]; } int nxt(int x){ insert(x);int ret=nxtv(); del(x);return val[ret]; } int n,m; inline int rd(){ int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } map<int,int> mp; int h[MAXN]; int aim[MAXN][2]; int f[MAXN][32],A[MAXN][32],B[MAXN][32]; int LEN; void solve1(){ int X0,sa,sb,fans; X0=rd(); int pos,sav=0; long double tmp,ans=1e9; for(R i=1;i<=n;i++){ pos=i;sav=0;sa=0;sb=0; for(R j=LEN;j>=0;j--){ if(f[pos][j]>n||f[pos][j]==0) continue;//==0 if(sav+A[pos][j]+B[pos][j]>X0) continue; sa+=A[pos][j];sb+=B[pos][j]; sav+=A[pos][j]+B[pos][j]; pos=f[pos][j]; } tmp=sa==0?1e9:1.0*sb/sa; if(tmp<ans){ans=tmp;fans=i;} else if(tmp==ans) fans=h[fans]>h[i]?fans:i; } printf("%d\n",fans); } void solve2(){ int x,y; x=rd();y=rd(); int pos=x; long long sav=0; long long ans1=0,ans2=0; for(R j=LEN;j>=0;j--){ if(f[pos][j]>n||f[pos][j]==0) continue;// if(sav+A[pos][j]+B[pos][j]>y) continue; ans1+=B[pos][j];ans2+=A[pos][j]; sav+=A[pos][j]+B[pos][j]; pos=f[pos][j]; } printf("%lld %lld\n",ans1,ans2); } int main(){ n=rd();LEN=log2(n); insert(INF);insert(-INF); for(R i=1;i<=n;i++) h[i]=rd(),mp[h[i]]=i; for(R i=n;i>=1;i--){ int pr=pre(h[i]),nx=nxt(h[i]),ppr=-INF,nnx=INF,tmp=INF; aim[i][0]=h[i]-pr<=nx-h[i]?pr:nx; if(pr!=-INF) ppr=pre(pr);if(nx!=INF) nnx=nxt(nx); int t=0,po=0; if(nx==aim[i][0]) t++,po=nx; if(nnx==aim[i][0]) t++,po=nnx; if(pr==aim[i][0]) t++,po=pr; if(ppr==aim[i][0]) t++,po=ppr; if(nx-h[i]<tmp&&nx!=aim[i][0]) tmp=nx-h[i],aim[i][1]=nx; if(nnx-h[i]<tmp&&nnx!=aim[i][0]) tmp=nnx-h[i],aim[i][1]=nnx; if(h[i]-pr<=tmp&&pr!=aim[i][0]) tmp=h[i]-pr,aim[i][1]=pr; if(h[i]-ppr<=tmp&&ppr!=aim[i][0]) tmp=h[i]-ppr,aim[i][1]=ppr; if(t>=2) aim[i][1]=po; insert(h[i]); } for(R i=1;i<=n;i++) for(R j=0;j<=1;j++) aim[i][j]=mp[aim[i][j]]; } for(R i=1;i<=n;i++){ f[i][0]=aim[i][1]; f[i][1]=aim[aim[i][1]][0]; B[i][0]=B[i][1]=abs(h[f[i][0]]-h[i]); A[i][1]=abs(h[f[i][0]]-h[f[i][1]]); A[i][0]=0; } for(R j=2;(1<<j)<=n;j++){ for(R i=1;i<=n;i++){ f[i][j]=f[f[i][j-1]][j-1]; A[i][j]=A[i][j-1]+A[f[i][j-1]][j-1]; B[i][j]=B[i][j-1]+B[f[i][j-1]][j-1]; } } solve1(); m=rd(); while(m--) solve2(); return 0; }
本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9382784.html