您的位置:首页 > 其它

[树链剖分+李超线段树] 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)。

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: