[SDOI2016]游戏 树剖+李超树
Posted dsrdsr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SDOI2016]游戏 树剖+李超树相关的知识,希望对你有一定的参考价值。
链接
https://www.luogu.org/problemnew/show/P4069
思路
树剖+超哥线段树
我已经自毙了,自闭了!!!!
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const ll N=400007LL;
const ll inf=123456789123456789LL;
ll read() {
ll x=0,f=1;char s=getchar();
for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
return x*f;
}
struct node {
ll v,nxt,q;
}e[N<<1];
ll n,m,head[N<<1],tot;
ll top[N],idx[N],fun[N],siz[N],f[N],son[N],dep[N],dis[N],js;
void add(ll u,ll v,ll q) {
e[++tot].v=v,e[tot].q=q,e[tot].nxt=head[u],head[u]=tot;
}
namespace seg_tree {
#define ls rt<<1
#define rs rt<<1|1
struct node {
ll l,r;
ll a,b,mi,t;
}e[N<<2];
bool tag[N<<2];
ll calc(ll a,ll b,ll id) {return a*dis[fun[id]]+b;}
void build(ll l,ll r,ll rt) {
e[rt].l=l,e[rt].r=r;
e[rt].b=e[rt].mi=inf;
if(l==r) return;
ll mid=(l+r)>>1;
build(l,mid,ls);
build(mid+1,r,rs);
}
bool cmp(ll a,ll b,ll c,ll d,ll id) {return calc(a,b,id)>calc(c,d,id);}
void modify(ll l,ll r,ll a,ll b,ll L,ll R,ll rt) {
if(L<=e[rt].l&&e[rt].r<=R) {//写法注意
// if(cmp(a,b,e[rt].a,e[rt].b,e[rt].l)&&cmp(a,b,e[rt].a,e[rt].b,e[rt].r)) return;
// if(cmp(e[rt].a,e[rt].b,a,b,e[rt].l)&&cmp(e[rt].a,e[rt].b,a,b,e[rt].r)) {
// tag[rt]=1;
// e[rt].a=a,e[rt].b=b;
// e[rt].mi=min(e[rt].mi,(calc(a,b,e[rt].l),calc(a,b,e[rt].r)));
// return;
// }
// if(e[rt].l==e[rt].r) return;
bool cmp1 = (calc(e[rt].a,e[rt].b,l) <= calc(a,b,l));
bool cmp2 = (calc(e[rt].a,e[rt].b,r) <= calc(a,b,r));
if (cmp1 && cmp2) return;
if ((!cmp1) && (!cmp2)) {
tag[rt]=1;
e[rt].mi = min(e[rt].mi, min(calc(a,b,l), calc(a,b,r)));
e[rt].a=a,e[rt].b=b;
// cout<<l<<" "<<r<<" "<<e[rt].mi<<"<<<<<<<<
";
return;
}
ll mid=(e[rt].l+e[rt].r)>>1;
bool cmp3 = (calc(e[rt].a,e[rt].b,mid) <= calc(a,b,mid));
if (!cmp3) {
swap(e[rt].a,a);swap(e[rt].b,b);swap(cmp1, cmp2);
}
if (cmp2) {
modify(l,mid,a,b,L,R,ls);
} else {
modify(mid+1,r,a,b,L,R,rs);
}
e[rt].mi= min(min(e[ls].mi, e[rs].mi), min(calc(e[rt].a,e[rt].b,l), calc(e[rt].a,e[rt].b,r)));
return;
}
ll mid=(e[rt].l+e[rt].r)>>1;
if(L<=mid) modify(l,mid,a,b,L,R,ls);
if(R>mid) modify(mid+1,r,a,b,L,R,rs);
e[rt].mi= min(min(e[ls].mi, e[rs].mi), min(calc(e[rt].a,e[rt].b,l), calc(e[rt].a,e[rt].b,r)));
// pushup(rt);
}
ll query(ll l,ll r,ll L,ll R,ll rt) {
if(L<=e[rt].l&&e[rt].r<=R) {
// cout<<e[rt].l<<" "<<e[rt].r<<"!!
";
// cout<<e[rt].mi<<"!!
";
return e[rt].mi;
}
ll mid=(e[rt].l+e[rt].r)>>1;
// int ans = min(ans, min(cal(lp, bst[pos]), cal(rp, bst[pos])));
ll ans= min(calc(e[rt].a,e[rt].b,max(L,l)),calc(e[rt].a,e[rt].b,min(r,R))) ;//注意
if(L<=mid) ans=min(query(l, mid,L,R,ls),ans);
if(R>mid) ans=min(query(mid+1,r,L,R,rs),ans);
return ans;
}
}
namespace tree {
void dfs1(ll u,ll fa) {
siz[u]=1;
f[u]=fa;
dep[u]=dep[fa]+1;
for(ll i=head[u];i;i=e[i].nxt) {
ll v=e[i].v;
if(v==fa) continue;
dis[v]=dis[u]+e[i].q;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v]) son[u]=v;
}
}
void dfs2(ll u,ll topf) {
top[u]=topf;
idx[u]=++js;
fun[js]=u;
if(son[u]) dfs2(son[u],topf);
for(ll i=head[u];i;i=e[i].nxt) {
ll v=e[i].v;
if(!idx[v]) dfs2(v,v);
}
}
ll lca(ll s,ll t) {
while(top[s]!=top[t]) {
if(dep[top[s]]<dep[top[t]]) swap(s,t);
s=f[top[s]];
}
return dep[s]<dep[t] ? s : t;
}
void CC(ll s,ll t,ll a,ll b) {
while(top[s]!=top[t]) {
if(dep[top[s]]<dep[top[t]]) swap(s,t);
seg_tree:: modify(1,n,a,b,idx[top[s]],idx[s],1);
s=f[top[s]];
}
if(dep[s]>dep[t]) swap(s,t);
seg_tree::modify(1,n,a,b,idx[s],idx[t],1);
}
void QQ(ll s,ll t) {
ll ans=inf;
while(top[s]!=top[t]) {
if(dep[top[s]]<dep[top[t]]) swap(s,t);
ans=min(ans,seg_tree::query(1,n,idx[top[s]],idx[s],1));
// cout<<idx[top[s]]<<" "<<idx[s]<<"
";
s=f[top[s]];
}
if(dep[s]>dep[t]) swap(s,t);
ans=min(ans,seg_tree::query(1,n,idx[s],idx[t],1));
// cout<<idx[s]<<" "<<idx[t]<<"
";
printf("%lld
",ans);
}
}
int main() {
// freopen("game2.in","r",stdin);
// freopen("a.out","w",stdout);
n=read(),m=read();
for(ll i=1;i<n;++i) {
ll x=read(),y=read(),z=read();
add(x,y,z),add(y,x,z);
}
tree::dfs1(1,0);
tree::dfs2(1,1);
seg_tree::build(1,n,1);
for(ll i=1;i<=m;++i) {
ll opt=read(),s=read(),t=read();
if(opt==1) {
ll a=read(),b=read();
ll LCA=tree::lca(s,t);
tree::CC(s,LCA,-a,a*dis[s]+b);
tree::CC(t,LCA,a,a*dis[s]-2LL*a*dis[LCA]+b);
// cout<<LCA<<"<
";
// cout<<-a<<" "<<a*dis[s]+b<<"<
";
// cout<<LCA<<" "<<t<<"
";
// cout<<a<<" "<<a*dis[s]-2LL*a*dis[LCA]+b<<"<
";
} else tree::QQ(s,t);
}
return 0;
}
以上是关于[SDOI2016]游戏 树剖+李超树的主要内容,如果未能解决你的问题,请参考以下文章