日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

洛谷P2497:基站建设(splay、斜率优化)

發布時間:2023/12/3 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 洛谷P2497:基站建设(splay、斜率优化) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

所謂splay斜率優化dp,就是利用splay和斜率對dp進行優化

(逃)

解析

在斜優的時候,有時我們會發現我們插入的點的橫坐標并不單調
這個時候我們就無法利用單調隊列維護凸包了
這時,我們就要請出今天的主角:splay

插點

splay斜優最容易錯的一個地方
我們維護一個以結點橫坐標作為關鍵值的splay
結點記錄第信息有:左右兒子、父親、xy坐標、分別與左右兩邊第一個結點的斜率
注意這個第一個結點不一定是左右兒子!
特別的,沒有兒子時賦值成正(右)負(左)無窮

step1

首先,讓我們把結點按照splay的常規操作塞進去

if(!rt){rt=New(x,y,id,0);lk[rt]=-2e18;rk[rt]=2e18;return;}int now=rt;while(1){if(tr[now][x>dx[now]]) now=tr[now][x>dx[now]];else{tr[now][x>dx[now]]=New(x,y,id,now);splay(tot);break;}}

step2

但是這樣,可能凸包的性質會被打破
我們需要繼續維護凸包的性質
首先,這個結點可能會是兩邊的點變成需要去掉的上凸點
下面以左側為例

加入一個x點時:

顯然,3點和4點應該舍去
原本的點集滿足凸包性質的前提下
我們其實只需要找到左邊第一個滿足 lki<slope(i,x)lk_i<slope(i,x)lki?<slope(i,x)的點 (在本圖中就是2)
我們可以在splay上通過類似二分的方法來實現這個操作

inline int pre(){int now=tr[rt][0],res=0;while(now){if(lk[now]<slope(now,rt)+eps){res=now;now=tr[now][1];}else now=tr[now][0];}return res; }

找到這個pre之后,把pre和當前點之間的點全部刪去即可

if(tr[now][0]){int o=pre();//printf("?:\n");splay(o,now);tr[o][1]=0;lk[now]=rk[o]=slope(o,now);}

記得更新斜率!!!

step3

考慮到當前點本身可能就是上凸點
我們特判一下如果是直接把它刪掉即可
特判的依據就是lkx>rkxlk_x>rk_xlkx?>rkx?
注意這個特判必須在step2之后!!
為什么?因為x的lk和rk都是在step2求的…

if(lk[now]>rk[now]+eps){int ls=tr[now][0],rs=tr[now][1];f[ls]=0;rt=ls;tr[ls][1]=rs;f[rs]=ls;lk[rs]=rk[ls]=slope(ls,rs);}

查詢

對于一個斜率k
找到 lki≤k≤rkilk_i \leq k \leq rk_ilki?krki? 的位置即可
相對比較簡單

if(lk[now]>rk[now]+eps){int ls=tr[now][0],rs=tr[now][1];f[ls]=0;rt=ls;tr[ls][1]=rs;f[rs]=ls;lk[rs]=rk[ls]=slope(ls,rs);}

update

本題中的橫坐標兩兩不同,但有些題并非如此,需要特判橫坐標相同的情況!
具體而言,只需要在插點的地方這么寫:

int x;//這里維護的上凸包if(!now) rt=New(xx,yy,0),x=rt;else{while(1){if(abs(dx[now]-xx)<eps){if(dy[now]<yy) return;else{dy[now]=yy;splay(now);x=now;break;}}if(tr[now][xx>dx[now]]) now=tr[now][xx>dx[now]];else{tr[now][xx>dx[now]]=New(xx,yy,now);splay(tot);x=tot;break;}}}.......

代碼

主函數就變得非常easy!

#include<bits/stdc++.h> using namespace std; #define ll long long #define il inline #define debug(a) fprintf(stderr,a) const int N=5e5+1000; const int M=3e6+100; const int mod=998244353; const double eps=1e-10; inline ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f; } int n,m; int tr[N][2],f[N],idx[N],rt,tot; double lk[N],rk[N],dx[N],dy[N]; inline int New(double x,double y,int id,int fa){++tot;tr[tot][0]=tr[tot][1]=0;f[tot]=fa;dx[tot]=x;dy[tot]=y;idx[tot]=id;return tot; } inline bool which(int x){return tr[f[x]][1]==x;} inline void rotate(int x){int fa=f[x],gfa=f[fa];int d=which(x),son=tr[x][d^1];f[x]=gfa;if(gfa) tr[gfa][which(fa)]=x;f[fa]=x;tr[x][d^1]=fa;if(son) f[son]=fa;tr[fa][d]=son;return; } inline void splay(int x,int goal=0){//printf("x=%d goal=%d fa=%d\n",x,goal,f[x]);for(int fa;(fa=f[x])!=goal;rotate(x)){if(f[fa]!=goal) which(fa)==which(x)?rotate(fa):rotate(x);}if(!goal) rt=x;return; } #define slope(u,v) ((dy[v]-dy[u])/(dx[v]-dx[u])) inline int pre(){int now=tr[rt][0],res=0;while(now){if(lk[now]<slope(now,rt)+eps){res=now;now=tr[now][1];}else now=tr[now][0];}return res; } inline int nxt(){int now=tr[rt][1],res=0;while(now){if(rk[now]+eps>slope(rt,now)){res=now;now=tr[now][0];}else now=tr[now][1];}return res; } inline void ins(double x,double y,int id){if(!rt){rt=New(x,y,id,0);lk[rt]=-2e18;rk[rt]=2e18;return;}int now=rt;while(1){if(tr[now][x>dx[now]]) now=tr[now][x>dx[now]];else{tr[now][x>dx[now]]=New(x,y,id,now);splay(tot);break;}}//for(int i=1;i<=tot;i++) printf("i=%d ls=%d rs=%d (%.3lf %.3lf)\n",i,tr[i][0],tr[i][1],dx[i],dy[i]);now=rt;if(tr[now][0]){int o=pre();//printf("?:\n");splay(o,now);tr[o][1]=0;lk[now]=rk[o]=slope(o,now);}else lk[now]=-2e18;if(tr[now][1]){int o=nxt();splay(o,now);tr[o][0]=0;rk[now]=lk[o]=slope(o,now);}else rk[now]=2e18;if(lk[now]>rk[now]+eps){int ls=tr[now][0],rs=tr[now][1];f[ls]=0;rt=ls;tr[ls][1]=rs;f[rs]=ls;lk[rs]=rk[ls]=slope(ls,rs);}return; } int query(double k){int now=rt;while(1){if(!now) return 0;//printf("now=%d lk=%.3lf rk=%.3lf (%.3lf %.3lf)\n",now,lk[now],rk[now],dx[now],dy[now]);if(lk[now]-eps<=k&&k<=rk[now]+eps) return idx[now];else if(lk[now]+eps>k) now=tr[now][0];else now=tr[now][1];} } double ans=2e18; int v[N]; ll x[N]; double dp[N],r[N]; #define X(o) (-1.0/(2.0*sqrt(r[o]))) #define Y(o) (dp[o]-1.0*x[o]/(2*sqrt(r[o]))) int main() { #ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout); #endifn=read();m=read();for(int i=1;i<=n;i++){x[i]=read();r[i]=read();v[i]=read();}dp[1]=v[1];ins(X(1),Y(1),1);//printf(" i=%d dp=%.3lf (%.3lf,%.3lf)\n\n",1,dp[1],X(1),Y(1));for(int i=2;i<=n;i++){//printf("i=%d\n",i);int j=query(x[i]);//printf(" ok\n");dp[i]=dp[j]+1.0*(x[i]-x[j])/(2*sqrt(r[j]))+v[i];//printf(" j=%d i=%d dp=%.3lf (%.3lf,%.3lf)\n\n",j,i,dp[i],X(i),Y(i));ins(X(i),Y(i),i);if(x[i]+r[i]>=m) ans=min(ans,dp[i]);}//printf("ceck:%3lf\n",slope(1,2));printf("%.3lf\n",ans);return 0; } /* 3 1 3 1 33 2 1 1 2 3 1 3 */

總結

以上是生活随笔為你收集整理的洛谷P2497:基站建设(splay、斜率优化)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。