bzoj 4515: [Sdoi2016]游戏
Description
Alice 和 Bob 在玩一個游戲。 游戲在一棵有 n 個點的樹上進行。最初,每個點上都只有一個數字,那個數字是 123456789123456789。 有時,Alice 會選擇一條從 s 到 t 的路徑,在這條路徑上的每一個點上都添加一個數字。對于路徑上的一個點 r, 若 r 與 s 的距離是 dis,那么 Alice 在點 r 上添加的數字是 a×dis+b。有時,Bob 會選擇一條從 s 到 t 的路徑。 他需要先從這條路徑上選擇一個點,再從那個點上選擇一個數字。 Bob 選擇的數字越小越好,但大量的數字讓 Bob 眼花繚亂。Bob 需要你幫他找出他能夠選擇的最小的數字。Input
第一行兩個數字 n、m,表示樹的點數和進行的操作數。 接下來 n?1 行,每行三個數字 u、v、w,表示樹上有一條連接 u、v 的邊,長度是 w。 接下來 m 行。每行第一個數字是 1 或 2。 若第一個數是 1,表示 Alice 進行操作,接下來四個數字 s、t、a、b。 若第一個數是 2,表示 Bob 進行操作,接下來四個數字 s、t。Output
每當 Bob 進行操作,輸出一行一個數,表示他能夠選擇的最小的數字
Sample Input
3 51 2 10
2 3 20
2 1 3
1 2 3 5 6
2 2 3
1 2 3 -5 -6
2 2 3
Sample Output
1234567891234567896
-106
HINT
?n≤100000,m≤100000,∣a∣≤10000,0<=w,|b|<=10^9?
Source
鳴謝Menci上傳
?
SDOI驚現天天愛跑步的套路,首先a*dis+b,拆路徑來討論;
對于s-lca,變為a*(d[s]-d[i])+b,也就是-a*d[i]+a*d[s]+b;
對于lca-t,變為a*(d[s]+d[i]-2*d[lca]),也就是a*d[i]+a*(d[s]-2*d[lca])+b;
所以每個點的d[i],就相當于是一個橫坐標,然后對于這個點插入一個kx+b的直線;
因為樹鏈剖分的log個區間中每個區間的d[i]是遞增的;
那么就相當于對這一個區間插入了一條kx+b的直線;然后我們需要動態的維護每個節點的最小值;
那么因為橫坐標都是整點,我們可以用線段樹來維護這一個半平面交;
用一種比較特殊的標記永久化方法;標記在這個區間中的最小值在哪一條直線上;
然后區間插入直線的時候算出交點,然后分情況遞歸更改左右區間即可;具體做法看lych即可,太強了;
以下為蒯的:
不妨考慮標記永久化(這里只是一定程度上的永久化但還是要下傳的)。
讓線段樹中的一個節點只對應一條直線,那么如果在這個區間加入一條直線怎么辦呢?
要分類討論,設新加入的f1(x)=k1x+b1,原來的f2(x)=k2x+b2,左端點為l,右端點為r,那么有:
? ? ? ?1.f1(d[l])<f2(d[l])且f1(d[r])<f2(d[r]),對應一條直線在兩個端點都比另一條小,那么顯然在l~r中f1(x)處處比f2(x)小,直接把f2(x)替換為f1(x);
? ? ? ?2.同理若上式的兩個符號都為>,那么f1(x)處處不如f2(x)優,不做更改。
? ? ? ?3.k1<k2,那么由于不滿足1.2,顯然兩條直線有交點,此時解不等式f1(x)<f2(x)得到x>(b1-b2)/(k2-k1),那么判斷(b1-b2)/(k2-k1)在左半區間還是右半區間遞歸下傳即可;
? ? ? ?4.k1>k2同理。
? ? ? ?實際上這就是線段樹維護半平面交的過程~~~~~
? ? ? ?詢問就簡單多了,直接用標記永久化的線段樹的方法更新即可。
// MADE BY QT666 #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> #define lson x<<1 #define rson x<<1|1 #define int long long using namespace std; typedef long long ll; const int N=400050; const ll Inf=123456789123456789ll; int head[N],to[N],nxt[N],v[N],d[N],deep[N],cnt,n,m,tot; int size[N],dfn[N],id[N],tt,son[N],top[N],fa[N]; ll Min[N*4],lazy[N*4],k[N*4],b[N*4],ans; void lnk(int x,int y,int z){to[++cnt]=y,nxt[cnt]=head[x],v[cnt]=z,head[x]=cnt;to[++cnt]=x,nxt[cnt]=head[y],v[cnt]=z,head[y]=cnt; } void dfs1(int x,int f){size[x]=1;deep[x]=deep[f]+1;for(int i=head[x];i;i=nxt[i]){int y=to[i];if(y==f) continue;d[y]=d[x]+v[i];dfs1(y,x);fa[y]=x;size[x]+=size[y];if(size[y]>size[son[x]]) son[x]=y;} } void dfs2(int x,int f){top[x]=f;dfn[x]=++tt;id[tt]=x;if(son[x]) dfs2(son[x],f);for(int i=head[x];i;i=nxt[i]){int y=to[i];if(y==fa[x]||y==son[x]) continue;dfs2(y,y);} } struct data{int l,r,fl; }p[N]; int lca(int x,int y){tot=0;int fl=1;while(top[x]!=top[y]){if(deep[top[x]]<deep[top[y]]) swap(x,y),fl^=1;p[++tot]=(data){dfn[top[x]],dfn[x],fl};x=fa[top[x]];}if(deep[x]<deep[y]) swap(x,y),fl^=1;p[++tot]=(data){dfn[y],dfn[x],fl};return y; } void pushup(int x,int l,int r){if(l<r) Min[x]=min(Min[lson],Min[rson]);else Min[x]=Inf;if(lazy[x]){Min[x]=min(Min[x],min(k[x]*d[id[l]],k[x]*d[id[r]])+b[x]);} } void build(int x,int l,int r){if(l==r){Min[x]=Inf;return;}int mid=(l+r)>>1;build(lson,l,mid);build(rson,mid+1,r);pushup(x,l,r); } void update(int x,int l,int r,ll K,ll B){if(!lazy[x]){lazy[x]=1;k[x]=K,b[x]=B;pushup(x,l,r);return;}ll x1=d[id[l]]*K+B,y1=d[id[r]]*K+B,x2=d[id[l]]*k[x]+b[x],y2=d[id[r]]*k[x]+b[x];if(x1<=x2&&y1<=y2){k[x]=K,b[x]=B;pushup(x,l,r);return;}else if(x2<=x1&&y2<=y1){return;}else if(K<k[x]){int mid=(l+r)>>1;int fj=(B-b[x])/(k[x]-K)+1;if(fj<=d[id[mid]]){swap(k[x],K);swap(b[x],B);update(lson,l,mid,K,B);}else update(rson,mid+1,r,K,B);pushup(x,l,r);}else if(K>k[x]){int mid=(l+r)>>1;int fj=(b[x]-B-1)/(K-k[x]);if(fj>d[id[mid]]){swap(k[x],K),swap(b[x],B);update(rson,mid+1,r,K,B);}else update(lson,l,mid,K,B);pushup(x,l,r);} } void insert(int x,int l,int r,int xl,int xr,ll K,ll B){if(xl<=l&&r<=xr){update(x,l,r,K,B);return;}int mid=(l+r)>>1;if(xr<=mid) insert(lson,l,mid,xl,xr,K,B);else if(xl>mid) insert(rson,mid+1,r,xl,xr,K,B);else insert(lson,l,mid,xl,mid,K,B),insert(rson,mid+1,r,mid+1,xr,K,B);pushup(x,l,r); } void query(int x,int l,int r,int xl,int xr){if(xl<=l&&r<=xr) {ans=min(ans,Min[x]);return;}int mid=(l+r)>>1;if(lazy[x]) ans=min(ans,min(k[x]*d[id[xl]],k[x]*d[id[xr]])+b[x]);if(xr<=mid) query(lson,l,mid,xl,xr);else if(xl>mid) query(rson,mid+1,r,xl,xr);else query(lson,l,mid,xl,mid),query(rson,mid+1,r,mid+1,xr); } main(){scanf("%lld%lld",&n,&m);for(int i=1;i<n;i++){int x,y,z;scanf("%lld%lld%lld",&x,&y,&z);lnk(x,y,z);}dfs1(1,0);dfs2(1,1);build(1,1,n);for(int i=1;i<=m;i++){int type;scanf("%lld",&type);if(type==1){int s,t,a,b;scanf("%lld%lld%lld%lld",&s,&t,&a,&b);int Lca=lca(s,t);ll k=a,b1=a*d[s]+b,b2=a*(d[s]-2*d[Lca])+b;for(int j=1;j<=tot;j++){if(p[j].fl==1) insert(1,1,n,p[j].l,p[j].r,-k,b1);else insert(1,1,n,p[j].l,p[j].r,k,b2);}}else{ans=Inf;int s,t;scanf("%lld%lld",&s,&t);int Lca=lca(s,t);for(int j=1;j<=tot;j++) query(1,1,n,p[j].l,p[j].r);printf("%lld\n",ans);}}return 0; }轉載于:https://www.cnblogs.com/qt666/p/7489179.html
總結
以上是生活随笔為你收集整理的bzoj 4515: [Sdoi2016]游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Map实现java缓存机制的简单实例
- 下一篇: centeros 安装mysql