BZOJ4515: [Sdoi2016]游戏
2017-12-01 20:59
232 查看
传送门(这篇写得比我好
qwq
s到t的链可以拆成两条纵链
令dis[x]表示x到根的距离
对于一条纵链上的一个点x,添加的数就可以看成
(dis[x]-dis[t])* k+b
=dis[x]*k-dis[t]*k+b
=k*dis[x]+B
很像直线的表达式y=kx+b
树剖,问题变成线段树维护多条直线在区间内的最小值
对于一条链,因为这个区间内的dis是递增的即x坐标递增,这个操作相当于给线段树一个区间上覆盖一条直线
在区间上打永久化标记为覆盖这个区间的直线,当遇到新的直线时,设加入直线f1,当前覆盖这个区间的直线f2,如果f1(l)< f2(l)&&f1(r)< f2(r) 那么可以用f1代替f2,都大于则没有用,否则递归下去,因为最多只有一个交点,这个交点不在左就在右,所以可以保证复杂度
code:
qwq
s到t的链可以拆成两条纵链
令dis[x]表示x到根的距离
对于一条纵链上的一个点x,添加的数就可以看成
(dis[x]-dis[t])* k+b
=dis[x]*k-dis[t]*k+b
=k*dis[x]+B
很像直线的表达式y=kx+b
树剖,问题变成线段树维护多条直线在区间内的最小值
对于一条链,因为这个区间内的dis是递增的即x坐标递增,这个操作相当于给线段树一个区间上覆盖一条直线
在区间上打永久化标记为覆盖这个区间的直线,当遇到新的直线时,设加入直线f1,当前覆盖这个区间的直线f2,如果f1(l)< f2(l)&&f1(r)< f2(r) 那么可以用f1代替f2,都大于则没有用,否则递归下去,因为最多只有一个交点,这个交点不在左就在右,所以可以保证复杂度
code:
#include<set> #include<map> #include<deque> #include<queue> #include<stack> #include<cmath> #include<ctime> #include<bitset> #include<string> #include<vector> #include<cstdio> #include<cstdlib> #include<cstring> #include<climits> #include<complex> #include<iostream> #include<algorithm> #define ll long long using namespace std; inline ll _min(const ll a,const ll b){return a<b?a:b;} inline void down(ll &x,const ll &y){if(x>y)x=y;} const int maxn = 210000; const int maxm = 210000; const ll inf = 123456789123456789ll; int n,m; struct edge { int y,c,nex; edge(){} edge(const int _y,const int _c,const int _nex){y=_y;c=_c;nex=_nex;} }a[maxn<<1]; int len,fir[maxn]; inline void ins(const int x,const int y,const int c){a[++len]=edge(y,c,fir[x]);fir[x]=len;} ll dis[maxn]; int f[maxn],top[maxn],siz[maxn],son[maxn],dep[maxn],w[maxn]; void dfs(const int x) { siz[x]=1; for(int k=fir[x];k;k=a[k].nex) { const int y=a[k].y; if(y!=f[x]) { dep[y]=dep[x]+1; dis[y]=dis[x]+(ll)a[k].c; f[y]=x; dfs(y); if(siz[son[x]]<siz[y]) son[x]=y; siz[x]+=siz[y]; } } } int z; ll s[maxn]; void build(const int x,const int tp) { s[w[x]=++z]=dis[x]; top[x]=tp; if(son[x]) build(son[x],tp); for(int k=fir[x];k;k=a[k].nex) { const int y=a[k].y; if(y!=f[x]&&y!=son[x]) build(y,y); } } struct segment { bool flag; ll a,b,mn; segment(){flag=false;mn=inf;} }seg[maxn<<2]; int lx,rx; ll fa,fb; void up(const int x) { int lc=x<<1,rc=lc|1; down(seg[x].mn,_min(seg[lc].mn,seg[rc].mn)); } void upd(const int x,const int l,const int r) { if(rx<l||r<lx) return; if(lx<=l&&r<=rx) { ll cl=s[l]*fa+fb,cr=s[r]*fa+fb; if(seg[x].flag) { ll cl2=s[l]*seg[x].a+seg[x].b,cr2=s[r]*seg[x].a+seg[x].b; if(cl>=cl2&&cr>=cr2) return; else if( (cl<cl2&&cr>=cr2)||(cl>=cl2&&cr<cr2) ) { int mid=l+r>>1,lc=x<<1,rc=lc|1; upd(lc,l,mid); upd(rc,mid+1,r); up(x); return; } } seg[x].flag=true; seg[x].a=fa,seg[x].b=fb; down(seg[x].mn,_min(cl,cr)); return; } int mid=l+r>>1,lc=x<<1,rc=lc|1; upd(lc,l,mid); upd(rc,mid+1,r); up(x); } ll ret; void query(const int x,const int l,const int r) { if(rx<l||r<lx) return; if(lx<=l&&r<=rx) { down(ret,seg[x].mn); return ; } int mid=l+r>>1,lc=x<<1,rc=lc|1; if(seg[x].flag) { ll cl=s[max(lx,l)]*seg[x].a+seg[x].b,cr=s[min(rx,r)]*seg[x].a+seg[x].b; down(ret,_min(cl,cr)); } query(lc,l,mid); query(rc,mid+1,r); } int LCA(int x,int y) { int f1=top[x],f2=top[y]; while(f1!=f2) { if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y); x=f[f1],f1=top[x]; } return dep[x]<dep[y]?x:y; } void change(int S,int T,int A,int B) { int tp=LCA(S,T),ft=top[tp]; int x=S,f1=top[x]; while(dep[x]>=dep[tp]) { if(f1==ft) f1=tp; fa=-A,fb=B+(ll)A*dis[S],lx=w[f1],rx=w[x],upd(1,1,n); x=f[f1],f1=top[x]; } int y=T,f2=top[y]; while(dep[y]>=dep[tp]) { if(f2==ft) f2=tp; fa=A,fb=B+(ll)A*(dis[S]-dis[tp]*2ll),lx=w[f2],rx=w[y],upd(1,1,n); y=f[f2],f2=top[y]; } } ll solve(int x,int y) { ll re=inf; int f1=top[x],f2=top[y]; while(f1!=f2) { if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y); lx=w[f1],rx=w[x],ret=inf,query(1,1,n); down(re,ret); x=f[f1],f1=top[x]; } if(dep[x]>dep[y]) swap(x,y); lx=w[x],rx=w[y],ret=inf,query(1,1,n); down(re,ret); return re; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { int x,y,c; scanf("%d%d%d",&x,&y,&c); ins(x,y,c); ins(y,x,c); } dep[1]=1; dfs(1); build(1,1); for(int i=1;i<=m;i++) { int type,s,t; scanf("%d%d%d",&type,&s,&t); if(type==1) { int A,B; scanf("%d%d",&A,&B); change(s,t,A,B); } else printf("%lld\n",solve(s,t)); } return 0; }
相关文章推荐
- [树链剖分+李超线段树] BZOJ4515: [Sdoi2016]游戏
- BZOJ4515: [Sdoi2016]游戏
- bzoj4515: [Sdoi2016]游戏
- Bzoj4515 [Sdoi2016]游戏
- bzoj4515 [Sdoi2016]游戏
- bzoj4600 [Sdoi2016]硬币游戏
- bzoj 4515: [Sdoi2016]游戏 树链剖分
- [bzoj4515][Sdoi2016]游戏-树链剖分+李超线段树
- [BZOJ4515][SDOI2016] 游戏 - 树链剖分 - 半平面交 - 标记永久化
- [SDOI 2016]游戏
- bzoj4600 [Sdoi2016]硬币游戏
- Bzoj4600--Sdoi2016硬币游戏
- 【BZOJ 4515】【SDOI 2016 Round1 Day1 T3】游戏
- bzoj 4515: [Sdoi2016]游戏 树链剖分+线段树
- [SDOI 2016] 硬币游戏
- BZOJ 4515 [Sdoi2016]游戏
- 【BZOJ4515】[Sdoi2016]游戏 树链剖分+线段树
- 4515: [Sdoi2016]游戏
- BZOJ 4515 [Sdoi2016]游戏
- bzoj 4515 [Sdoi2016]游戏 线段树维护凸包