原题传送门

看到这种题,想都不用想,先写一个树链剖分

然后发现修改操作增加的是等差数列,这使我们想到了李超线段树

先进性树剖,然后用李超线段树维护区间最小,这样就做完了(写码很容易出错)

复杂度为\(O(n\log^3n)\),少见的复杂度啊qaq,但常数不用怕

#include <bits/stdc++.h>
#define ll long long
#define N 100005
#define M 100005
#define inf 123456789123456789LL
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline ll read()
{
register ll x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register ll x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[25];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
inline ll Min(register ll a,register ll b)
{
return a<b?a:b;
}
struct edge{
int to,next;
ll v;
}e[M<<1];
int head[N],cnt=0;
inline void add(register int u,register int v,register ll w)
{
e[++cnt]=(edge){v,head[u],w};
head[u]=cnt;
}
inline ll f(register ll x,register ll k,register ll b)
{
return x*k+b;
}
struct node{
ll a,b,minn;
}tr[N<<2];
int n,m;
int size[N],fa[N],son[N],dep[N];
int pl[N],top[N],tot=0;
ll dis[N],pre[N];
inline void build(register int x,register int l,register int r)
{
tr[x].a=0,tr[x].b=tr[x].minn=inf;
if(l==r)
return;
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
}
inline void dfs1(register int x)
{
size[x]=1;
for(register int i=head[x];i;i=e[i].next)
if(e[i].to!=fa[x])
{
fa[e[i].to]=x;
dep[e[i].to]=dep[x]+1;
dis[e[i].to]=dis[x]+e[i].v;
dfs1(e[i].to);
if(size[e[i].to]>size[son[x]])
son[x]=e[i].to;
size[x]+=size[e[i].to];
}
}
inline void dfs2(register int x,register int t)
{
pl[x]=++tot,pre[tot]=dis[x],top[x]=t;
if(son[x])
dfs2(son[x],t);
for(register int i=head[x];i;i=e[i].next)
if(e[i].to!=son[x]&&e[i].to!=fa[x])
dfs2(e[i].to,e[i].to);
}
inline int getlca(register int x,register int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
x^=y^=x^=y;
x=fa[top[x]];
}
if(dep[x]>dep[y])
x^=y^=x^=y;
return x;
}
inline void Change(register int x,register int l,register int r,register ll a,register ll b)
{
int mid=l+r>>1,fl,fr,fm;
fl=(f(pre[l],tr[x].a,tr[x].b)>f(pre[l],a,b));
fr=(f(pre[r],tr[x].a,tr[x].b)>f(pre[r],a,b));
fm=(f(pre[mid],tr[x].a,tr[x].b)>f(pre[mid],a,b));
if(fl&&fr&&fm)
{
tr[x].a=a,tr[x].b=b,tr[x].minn=Min(tr[x].minn,Min(f(pre[l],a,b),f(pre[r],a,b)));
return;
}
if(!(fl|fr|fm))
return;
if(fm)
{
if(fr)
Change(x<<1,l,mid,tr[x].a,tr[x].b);
else
Change(x<<1|1,mid+1,r,tr[x].a,tr[x].b);
tr[x].a=a,tr[x].b=b,tr[x].minn=Min(tr[x].minn,Min(f(pre[l],a,b),f(pre[r],a,b)));
}
else
{
if(!fr)
Change(x<<1,l,mid,a,b);
else
Change(x<<1|1,mid+1,r,a,b);
}
tr[x].minn=Min(tr[x].minn,Min(tr[x<<1].minn,tr[x<<1|1].minn));
}
inline void change(register int x,register int l,register int r,register int L,register int R,register ll a,register ll b)
{
if(L<=l&&r<=R)
{
Change(x,l,r,a,b);
return;
}
int mid=l+r>>1;
if(L<=mid)
change(x<<1,l,mid,L,R,a,b);
if(R>mid)
change(x<<1|1,mid+1,r,L,R,a,b);
tr[x].minn=Min(tr[x].minn,Min(tr[x<<1].minn,tr[x<<1|1].minn));
}
inline void cal1(register int s,register int t,register ll a,register ll b)
{
int lca=getlca(s,t);
int x=s,y=t;
while(top[x]!=top[lca])
{
change(1,1,n,pl[top[x]],pl[x],-a,a*dis[s]+b);
x=fa[top[x]];
}
change(1,1,n,pl[lca],pl[x],-a,a*dis[s]+b);
while(top[y]!=top[lca])
{
change(1,1,n,pl[top[y]],pl[y],a,dis[s]*a-dis[lca]*2*a+b);
y=fa[top[y]];
}
if(y!=lca)
change(1,1,n,pl[lca]+1,pl[y],a,dis[s]*a-dis[lca]*2*a+b);
}
inline ll query(register int x,register int l,register int r,register int L,register int R)
{
ll res=Min(f(pre[L],tr[x].a,tr[x].b),f(pre[R],tr[x].a,tr[x].b));
if(L==l&&r==R)
return Min(res,tr[x].minn);
int mid=l+r>>1;
if(R<=mid)
return Min(res,query(x<<1,l,mid,L,R));
else if(L>mid)
return Min(res,query(x<<1|1,mid+1,r,L,R));
else
return Min(res,Min(query(x<<1,l,mid,L,mid),query(x<<1|1,mid+1,r,mid+1,R)));
}
inline ll cal2(register int s,register int t)
{
int x=s,y=t;
ll res=inf;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
x^=y^=x^=y;
res=Min(res,query(1,1,n,pl[top[x]],pl[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y])
x^=y^=x^=y;
res=Min(res,query(1,1,n,pl[x],pl[y]));
return res;
}
int main()
{
n=read(),m=read();
for(register int i=1;i<=n-1;++i)
{
int u=read(),v=read();
ll w=read();
add(u,v,w),add(v,u,w);
}
dfs1(1);
dfs2(1,1);
build(1,1,n);
while(m--)
{
int opt=read();
if(opt==1)
{
int s=read(),t=read();
ll a=read(),b=read();
cal1(s,t,a,b);
}
else
{
int s=read(),t=read();
write(cal2(s,t)),puts("");
}
}
return 0;
}

【题解】Luogu P4069 [SDOI2016]游戏的更多相关文章

  1. 洛谷P4069 [SDOI2016]游戏(李超线段树)

    题面 传送门 题解 如果我们把路径拆成两段,那么这个路径加可以看成是一个一次函数 具体来说,设\(dis_u\)表示节点\(u\)到根节点的距离,那么\((x,lca)\)这条路径上每个节点的权值就会 ...

  2. 洛谷P4069 [SDOI2016]游戏(李超线段树)

    题意 题目链接 Sol 这题细节好多啊qwq..稍不留神写出一个小bug就要调1h+.. 思路就不多说了,把询问区间拆成两段就是李超线段树板子题了. 关于dis的问题可以直接维护. // luogu- ...

  3. Luogu 4069 [SDOI2016]游戏

    BZOJ 4515 树链剖分 + 李超线段树 要求支持区间插入一条线段,然后查询一个区间内的最小值.可以使用李超线段树解决,因为要维护一个区间内的最小值,所以每一个结点再维护一个$res$表示这个区间 ...

  4. 【BZOJ4515】[Sdoi2016]游戏 树链剖分+线段树

    [BZOJ4515][Sdoi2016]游戏 Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 1234567 ...

  5. 4515: [Sdoi2016]游戏

    4515: [Sdoi2016]游戏 链接 分析: 树链剖分 + 超哥线段树.注意细节. 代码: #include<cstdio> #include<algorithm> #i ...

  6. [luogu]P1070 道路游戏[DP]

    [luogu]P1070 道路游戏 题目描述小新正在玩一个简单的电脑游戏.游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针 ...

  7. [Luogu P3825] [NOI2017] 游戏 (2-SAT)

    [Luogu P3825] [NOI2017] 游戏 (2-SAT) 题面 题面较长,略 分析 看到这些约束,应该想到这是类似2-SAT的问题.但是x地图很麻烦,因为k-SAT问题在k>2的时候 ...

  8. [题解] Luogu P5446 [THUPC2018]绿绿和串串

    [题解] Luogu P5446 [THUPC2018]绿绿和串串 ·题目大意 定义一个翻转操作\(f(S_n)\),表示对于一个字符串\(S_n\), 有\(f(S)= \{S_1,S_2,..., ...

  9. 【luogu P1558 色板游戏】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1558 我知道三十棵线段树很暴力,可是我们可以状压啊. 颜色最多30,不会爆int 另外 吐槽评测机 #inc ...

随机推荐

  1. 解决 AutoMapper ProjectTo 不起作用的问题

    这两天在一个 ASP.NET Core 项目中遭遇了 AutoMapper ProjectTo 不起作用的奇怪问题,虽然在 ProjectTo 中指定了 DTO ,但 EF Core 生成的 SQL ...

  2. yum配置163源

    CentOS7 配置163 yum源 1)下载repo文件 wget http://mirrors.163.com/.help/CentOS7-Base-163.repo 2)备份并替换系统的repo ...

  3. Python 学习笔记6 变量-字典

    字典是python中一个十分重要的变量,他是一个可变的容器对象.通过一组key(键)和value(值)对组成一个元素. 组成形式为{'key':'value', 'key':'value'}.整个字典 ...

  4. [Day18]集合框架Collection、迭代器、增强for循环以及泛型

    1.集合 1.1集合-本身是一个存储的容器 集合类的基本接口是Collection接口,这个接口有两个基本方法 (1)boolean add(E element) 用于向集合中添加元素,如果添加元素确 ...

  5. python GUI图形化编程-----wxpython

    一.python gui(图形化)模块介绍: Tkinter :是python最简单的图形化模块,总共只有14种组建 Pyqt     :是python最复杂也是使用最广泛的图形化 Wx       ...

  6. ytkah常用网址导航 关于网站运营等

    关于运营的网站 人人都是产品经理 产品100 爱运营 A5网站运营 姑婆那些事儿 馒头商学院 运营者 91运营网 互联网的一些事 jb51网站运营 三联网站运营 从零开始做运营 ​ 科技/互联网 cn ...

  7. plsql导入.dmp, .sql步骤

    plsql导入.sql和.dmp文件时,会经常用到,对于初学者来说可能没有那么简单,毕竟oracle数据库比较麻烦. 下面是我自己导入.sql和.dmp文件的步骤. 1.导入.sql文件(sql文件是 ...

  8. 输入参数的默认值设定${3:-var_d}

    今天看到一个不一样的写法: if [ $# != 2 ] && [ $# != 3 ] ; then #判断参数个数    echo "Invalid Args"  ...

  9. 六、latex中的特殊字符

  10. Git使用之pull request

    一直对git的使用都不熟,由于工作需要经常需要在github上pull request,第一次还是有些麻烦的,写个笔记记录下 1. fork源项目到自己的github仓库中 fork之后自己也会多出一 ...