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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

P2305 [NOI2014] 购票(点分治、斜率优化)

發布時間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P2305 [NOI2014] 购票(点分治、斜率优化) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

解析

第一道完全自己做出來的黑題awa
(如果不算那道感覺完全是惡評的石油的話)
然而連寫帶調整了3.5h…

容易想到鏈的做法
ancxanc_xancx?表示x的祖先,disxdis_xdisx?表示x到1的距離
則有:
dpv=min?disv?lv<=disu,u∈ancv(dpu+pv×(disv?disu)+qvdp_v=\min_{dis_v-l_v<=dis_u,u\in anc_v}(dp_u+p_v\times (dis_v-dis_u)+q_vdpv?=disv??lv?<=disu?,uancv?min?(dpu?+pv?×(disv??disu?)+qv?
這個就可以斜優了

然后考慮如何上樹
樹比較惡心的地方就是我們的隊列會隨著dfs分支的改變而變化
難以解決

換個思路
考慮點分治
對與當前的重心 rt,
先把rt到1的那個聯通塊遞歸solve掉
然后再把聯通塊內rt的返祖鏈取下來
再dfs找到所有聯通塊內的其他點
按照能到達的最大高度sort一下
然后做個指針動態維護這個凸包,二分更新就行了

代碼

#include<bits/stdc++.h> using namespace std; #define ll __int128 #define inf (n+1) //#define debug(...) fprintf(stderr,__VA_ARGS__) const int N=2e5+100; const int M=2e5+10500; const double eps=1e-5; 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<<1)+(x<<3)+c-'0';c=getchar();}return x*f; } void write(ll x){if(x<0){putchar('-');x=-x;}if(x>9) write(x/10);putchar('0'+x%10);return; }int n,m; int debug(0);struct node{int to,nxt;ll w; }p[N<<1]; int fi[N],cnt; inline void addline(int x,int y,ll w){p[++cnt]=(node){y,fi[x],w};fi[x]=cnt;return; }ll dp[N],P[N],Q[N],dis[N],l[N]; int fa[N],siz[N],mx[N],S,rt; int que[N],num1; int v[N],num2; bool vis[N];void find(int x,int f){siz[x]=1;mx[x]=0;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f||vis[to]) continue;find(to,x);siz[x]+=siz[to];mx[x]=max(mx[x],siz[to]);} mx[x]=max(mx[x],S-siz[x]);if(!rt||mx[rt]>mx[x]) rt=x;return; }void dfs(int x,int top){que[++num1]=x;//if(debug) printf("dfs:x=%d f=%d tot=%d\n",x,f,tot);if(x==top) return;dfs(fa[x],top);return; }#define X(o) dis[o] #define Y(o) dp[o] int q[N],le,ri;inline void upd(int x){int st=le,ed=ri;while(st<ed){int mid=(st+ed)>>1,o=q[mid];if(dis[x]-dis[o]>l[x]||(mid<ri&&P[x]*(X(q[mid+1])-X(q[mid]))>=(Y(q[mid+1])-Y(q[mid])))) st=mid+1;else ed=mid;//if(debug) printf(" mid=%d o=%d d=%lld %d||(%d&&%d) (%d %d)\n",mid,o,(long long)(dis[x]-dis[o]),dis[x]-dis[o]>l[x],mid<tot,P[x]*(X(q[num+1])-X(q[num]))>=(Y(q[num+1])-Y(q[num])),st,ed);}if(st==ed&&dis[x]-dis[q[st]]<=l[x]){int u=q[st];dp[x]=min(dp[x],P[x]*(dis[x]-dis[u])+dp[u]+Q[x]);if(debug) printf(" update: x=%d u=%d dp=%lld\n",x,u,(long long)dp[x]);}return; }inline void add(int x){if(debug) printf(" add:x=%d (%lld %lld)\n",x,(long long)X(x),(long long)Y(x));while(le<ri&&(Y(q[le])-Y(x))*(X(q[le+1])-X(q[le]))>=(Y(q[le+1])-Y(q[le]))*(X(q[le])-X(x))) ++le;q[--le]=x;if(debug) for(int i=le;i<=ri;i++) printf("[%d]:(%lld %lld) ",q[i],(long long)X(q[i]),(long long)Y(q[i]));if(debug) putchar('\n');return; }void get(int x,int f){v[++num2]=x;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f||vis[to]) continue;get(to,x);}return; } int findtop(int x){return fa[x]&&!vis[fa[x]]?findtop(fa[x]):x; } int calc(int x,int f){int res(1);for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f||vis[to]) continue;res+=calc(to,x);}return res; } bool cmp(int x,int y){return dis[x]-l[x]>dis[y]-l[y]; } void solve(int x){S=calc(x,0);rt=0;find(x,0);x=rt;vis[x]=1;int top=findtop(x);if(debug) printf("\nsolve: %d (S=%d top=%d)\n",x,S,top);if(fa[x]&&!vis[fa[x]]){solve(fa[x]);}if(debug) printf("\nbeginwork:%d\n",x);num1=0;num2=0;dfs(x,top);for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(vis[to]||to==fa[x]) continue;get(to,x);}sort(v+1,v+1+num2,cmp);if(debug){printf("que:");for(int i=1;i<=num1;i++) printf("%d ",que[i]);putchar('\n');printf("v:");for(int i=1;i<=num2;i++) printf("%d ",v[i]);putchar('\n');}for(int i=1;i<=num1;i++){int u=que[i];if(dis[x]-dis[u]>l[x]) break;dp[x]=min(dp[x],dp[u]+P[x]*(dis[x]-dis[u])+Q[x]);}int pl=1;ri=n;le=n+1;for(int i=1;i<=num2;i++){while(pl<=num1&&dis[v[i]]-l[v[i]]<=dis[que[pl]]){add(que[pl]);++pl;}upd(v[i]);}for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(vis[to]) continue;solve(to);}return; }void init(int x,int f){for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dis[to]=dis[x]+p[i].w;init(to,x);}return; } int main(){ #ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout); #endifmemset(fi,-1,sizeof(fi));cnt=-1;n=read();int zhennanrencongbuxiebufenfen=read();//assert(zhennanrencongbuxiebufenfen<=3);for(int i=2;i<=n;i++) dp[i]=2e18;dp[1]=0;for(int i=2;i<=n;i++){fa[i]=read();ll w=read();P[i]=read();Q[i]=read();l[i]=read();addline(fa[i],i,w);addline(i,fa[i],w);}init(1,0);siz[1]=n;solve(1);for(int i=2;i<=n;i++) write(dp[i]),putchar('\n');return 0; } /**/

總結

以上是生活随笔為你收集整理的P2305 [NOI2014] 购票(点分治、斜率优化)的全部內容,希望文章能夠幫你解決所遇到的問題。

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