[树链剖分+李超线段树] BZOJ4515: [Sdoi2016]游戏
2017-12-02 06:19
513 查看
先进行转化,把路径分成两条链,a(deps−depi)+b=(−a)∗depi+a∗deps+b…类似这样变形一下,就转化成和 k∗depi+b 的形式。depi 是递增的,所以可以看做是一次函数 y=kx+b 在某些离散的点上有定义。
现在需要实现区间插入线段,求区间最小值。这个问题可以用一个称为超哥线段树的技巧解决。
大概就是线段树节点记一条线段作为标记,标记如何合并呢?不太好直接合并。
其实可以算一下两个线段的优势区间,当前区间保留长的,短的在对应儿子上继续打标记。这样打标记是 O(logn) 的。
可以标记永久化,即不下传标记,减小常数。询问时需要用和询问区间有交的区间都更新一下答案。
总复杂度 O(nlog3n)。
现在需要实现区间插入线段,求区间最小值。这个问题可以用一个称为超哥线段树的技巧解决。
大概就是线段树节点记一条线段作为标记,标记如何合并呢?不太好直接合并。
其实可以算一下两个线段的优势区间,当前区间保留长的,短的在对应儿子上继续打标记。这样打标记是 O(logn) 的。
可以标记永久化,即不下传标记,减小常数。询问时需要用和询问区间有交的区间都更新一下答案。
总复杂度 O(nlog3n)。
#include<cstdio> #include<cmath> #include<cctype> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; inline char gc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int getint(){ char ch=gc(); int res=0,ff=1; while(!isdigit(ch)) ch=='-'?ff=-1:0, ch=gc(); while(isdigit(ch)) res=(res<<3)+(res<<1)+ch-'0', ch=gc(); return res*ff; } const int maxn=100005,maxe=200005; const LL INF=4e18; int n,Q,fir[maxn],nxt[maxe],son[maxe],w[maxe],tot; int sz[maxn],hvy[maxn],pre[maxn],top[maxn],pos[maxn],df[maxn]; LL dep[maxn]; void add(int x,int y,int z){ son[++tot]=y; w[tot]=z; nxt[tot]=fir[x]; fir[x]=tot; } struct node{ LL fk,fb,_min; node* ch[2]; node(node* son=NULL){ fk=fb=_min=INF; ch[0]=ch[1]=son; } inline void maintain(int L,int R){ if(L<R) _min=min(_min,min(ch[0]->_min,ch[1]->_min)); if(fk<INF) _min=min(_min,min(fb,fk*(dep[df[R]]-dep[df[L]])+fb)); } } *root, nil, *null=&nil; typedef node* P_node; P_node Build(int L,int R){ P_node p=new node(null); if(L==R) return p; int mid=(L+R)>>1; p->ch[0]=Build(L,mid); p->ch[1]=Build(mid+1,R); return p; } void Push_tag(P_node p,int L,int R,LL k,LL b){ //printf("[%d,%d] %lld %lld\n",L,R,k,b); if(p->_min==INF){ p->fk=k; p->fb=b; p->maintain(L,R); return; } int mid=(L+R)>>1; LL lenL=dep[df[mid+1]]-dep[df[L]]; LL &fk=p->fk, &fb=p->fb; if(fk==k||L==R) fk=k, fb=min(fb,b); else if(k>fk&&b>fb) ; else if(k<fk&&b<fb) fk=k, fb=b; else if(k>fk&&b<=fb){ LL d=(fb-b)/(k-fk); if(d<lenL) Push_tag(p->ch[0],L,mid,k,b); else swap(fk,k), swap(fb,b), Push_tag(p->ch[1],mid+1,R,k,b+k*lenL); } else if(k<fk&&b>=fb){ LL d=(fb-b)/(k-fk)+1; if(d>=lenL) Push_tag(p->ch[1],mid+1,R,k,b+k*lenL); else swap(fk,k), swap(fb,b), Push_tag(p->ch[0],L,mid,k,b); } p->maintain(L,R); } void Updata(P_node p,int L,int R,int qL,int qR,LL k,LL b){ if(R<qL||qR<L) return; if(qL<=L&&R<=qR){ Push_tag(p,L,R,k,b+k*(dep[df[L]]-dep[df[qL]])); return; } int mid=(L+R)>>1; Updata(p->ch[0],L,mid,qL,qR,k,b); Updata(p->ch[1],mid+1,R,qL,qR,k,b); p->maintain(L,R); } LL _ORG=123456789123456789LL; LL Query(P_node p,int L,int R,int qL,int qR){ if(R<qL||qR<L) return _ORG; LL res=_ORG; if(p->fk<INF){ int t1=max(L,qL),t2=min(R,qR); res=min(p->fk*(dep[df[t1]]-dep[df[L]])+p->fb,p->fk*(dep[df[t2]]-dep[df[L]])+p->fb); } if(qL<=L&&R<=qR) return min(res,p->_min); int mid=(L+R)>>1; return min(res,min(Query(p->ch[0],L,mid,qL,qR),Query(p->ch[1],mid+1,R,qL,qR))); } void dfs_info(int x){ sz[x]=1; for(int j=fir[x];j;j=nxt[j]) if(son[j]!=pre[x]){ dep[son[j]]=dep[x]+w[j]; pre[son[j]]=x; dfs_info(son[j]); sz[x]+=sz[son[j]]; if(sz[hvy[x]]<sz[son[j]]) hvy[x]=son[j]; } } void build_chain(int x,int tp){ df[++df[0]]=x; pos[x]=df[0]; top[x]=tp; if(hvy[x]) build_chain(hvy[x],tp); for(int j=fir[x];j;j=nxt[j]) if(son[j]!=pre[x]) if(son[j]!=hvy[x]) build_chain(son[j],son[j]); } LL Chain_Query(int x,int y){ LL res=INF; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); res=min(res,Query(root,1,n,pos[top[x]],pos[x])); x=pre[top[x]]; } if(dep[x]>dep[y]) swap(x,y); return min(res,Query(root,1,n,pos[x],pos[y])); } int LCA(int x,int y){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); x=pre[top[x]]; } if(dep[x]>dep[y]) swap(x,y); return x; } LL Chain_Update(int _lca,int x,LL k,LL b){ while(top[x]!=top[_lca]){ Updata(root,1,n,pos[top[x]],pos[x],k,b+k*(dep[top[x]]-dep[_lca])); x=pre[top[x]]; } Updata(root,1,n,pos[_lca],pos[x],k,b); } void Solve(int u,int v,LL _a,LL _b){ int lca=LCA(u,v); Chain_Update(lca,u,-_a,_b+_a*(dep[u]-dep[lca])); Chain_Update(lca,v,_a,_b+_a*(dep[u]-dep[lca])); } int main(){ freopen("bzoj4515.in","r",stdin); freopen("bzoj4515.out","w",stdout); n=getint(); Q=getint(); for(int i=1;i<=n-1;i++){ int x=getint(),y=getint(),z=getint(); add(x,y,z); add(y,x,z); } dfs_info(1); build_chain(1,1); root=Build(1,n); while(Q--){ int _type=getint(),x=getint(),y=getint(),_a,_b; if(_type==1) _a=getint(), _b=getint(), Solve(x,y,_a,_b); else printf("%lld\n",Chain_Query(x,y)); } return 0; }
相关文章推荐
- [bzoj4515][Sdoi2016]游戏-树链剖分+李超线段树
- [树链剖分 李超线段树] BZOJ4515 [Sdoi2016] 游戏
- bzoj 4515: [Sdoi2016]游戏 树链剖分+线段树
- 【树链剖分+李超线段树】BZOJ4515(Sdoi2016)[游戏]题解
- 数据结构(树链剖分,线段树):SDOI 2016 游戏
- Bzoj4515 [Sdoi2016]游戏
- LOJ2269 [SDOI2017] 切树游戏 【FWT】【动态DP】【树链剖分】【线段树】
- 【BZOJ4519】【Sdoi2016】游戏 线段树
- bzoj4515: [Sdoi2016]游戏
- bzoj 4515: [Sdoi2016]游戏 树链剖分
- 【BZOJ4515】游戏,树链剖分+永久化标记线段树维护线段信息(李超线段树)
- [BZOJ4515][SDOI2016] 游戏 - 树链剖分 - 半平面交 - 标记永久化
- BZOJ 4515|SDOI 2016|游戏|树链剖分
- BZOJ4515: [Sdoi2016]游戏
- 【BZOJ-4515】游戏 李超线段树 + 树链剖分 + 半平面交
- bzoj 4515 [Sdoi2016]游戏 线段树维护凸包
- [BZOJ4515][Sdoi2016]游戏(树链剖分)
- BZOJ4515: [Sdoi2016]游戏
- 树链剖分+线段树【SDOI2011】 bzoj2243 染色
- 【BZOJ 4600】【SDOI 2016】硬币游戏