【题解】Luogu P4069 [SDOI2016]游戏
原题传送门
看到这种题,想都不用想,先写一个树链剖分
然后发现修改操作增加的是等差数列,这使我们想到了李超线段树
先进性树剖,然后用李超线段树维护区间最小,这样就做完了(写码很容易出错)
复杂度为\(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]游戏的更多相关文章
- 洛谷P4069 [SDOI2016]游戏(李超线段树)
题面 传送门 题解 如果我们把路径拆成两段,那么这个路径加可以看成是一个一次函数 具体来说,设\(dis_u\)表示节点\(u\)到根节点的距离,那么\((x,lca)\)这条路径上每个节点的权值就会 ...
- 洛谷P4069 [SDOI2016]游戏(李超线段树)
题意 题目链接 Sol 这题细节好多啊qwq..稍不留神写出一个小bug就要调1h+.. 思路就不多说了,把询问区间拆成两段就是李超线段树板子题了. 关于dis的问题可以直接维护. // luogu- ...
- Luogu 4069 [SDOI2016]游戏
BZOJ 4515 树链剖分 + 李超线段树 要求支持区间插入一条线段,然后查询一个区间内的最小值.可以使用李超线段树解决,因为要维护一个区间内的最小值,所以每一个结点再维护一个$res$表示这个区间 ...
- 【BZOJ4515】[Sdoi2016]游戏 树链剖分+线段树
[BZOJ4515][Sdoi2016]游戏 Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 1234567 ...
- 4515: [Sdoi2016]游戏
4515: [Sdoi2016]游戏 链接 分析: 树链剖分 + 超哥线段树.注意细节. 代码: #include<cstdio> #include<algorithm> #i ...
- [luogu]P1070 道路游戏[DP]
[luogu]P1070 道路游戏 题目描述小新正在玩一个简单的电脑游戏.游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针 ...
- [Luogu P3825] [NOI2017] 游戏 (2-SAT)
[Luogu P3825] [NOI2017] 游戏 (2-SAT) 题面 题面较长,略 分析 看到这些约束,应该想到这是类似2-SAT的问题.但是x地图很麻烦,因为k-SAT问题在k>2的时候 ...
- [题解] Luogu P5446 [THUPC2018]绿绿和串串
[题解] Luogu P5446 [THUPC2018]绿绿和串串 ·题目大意 定义一个翻转操作\(f(S_n)\),表示对于一个字符串\(S_n\), 有\(f(S)= \{S_1,S_2,..., ...
- 【luogu P1558 色板游戏】 题解
题目链接:https://www.luogu.org/problemnew/show/P1558 我知道三十棵线段树很暴力,可是我们可以状压啊. 颜色最多30,不会爆int 另外 吐槽评测机 #inc ...
随机推荐
- 解决 AutoMapper ProjectTo 不起作用的问题
这两天在一个 ASP.NET Core 项目中遭遇了 AutoMapper ProjectTo 不起作用的奇怪问题,虽然在 ProjectTo 中指定了 DTO ,但 EF Core 生成的 SQL ...
- yum配置163源
CentOS7 配置163 yum源 1)下载repo文件 wget http://mirrors.163.com/.help/CentOS7-Base-163.repo 2)备份并替换系统的repo ...
- Python 学习笔记6 变量-字典
字典是python中一个十分重要的变量,他是一个可变的容器对象.通过一组key(键)和value(值)对组成一个元素. 组成形式为{'key':'value', 'key':'value'}.整个字典 ...
- [Day18]集合框架Collection、迭代器、增强for循环以及泛型
1.集合 1.1集合-本身是一个存储的容器 集合类的基本接口是Collection接口,这个接口有两个基本方法 (1)boolean add(E element) 用于向集合中添加元素,如果添加元素确 ...
- python GUI图形化编程-----wxpython
一.python gui(图形化)模块介绍: Tkinter :是python最简单的图形化模块,总共只有14种组建 Pyqt :是python最复杂也是使用最广泛的图形化 Wx ...
- ytkah常用网址导航 关于网站运营等
关于运营的网站 人人都是产品经理 产品100 爱运营 A5网站运营 姑婆那些事儿 馒头商学院 运营者 91运营网 互联网的一些事 jb51网站运营 三联网站运营 从零开始做运营 科技/互联网 cn ...
- plsql导入.dmp, .sql步骤
plsql导入.sql和.dmp文件时,会经常用到,对于初学者来说可能没有那么简单,毕竟oracle数据库比较麻烦. 下面是我自己导入.sql和.dmp文件的步骤. 1.导入.sql文件(sql文件是 ...
- 输入参数的默认值设定${3:-var_d}
今天看到一个不一样的写法: if [ $# != 2 ] && [ $# != 3 ] ; then #判断参数个数 echo "Invalid Args" ...
- 六、latex中的特殊字符
- Git使用之pull request
一直对git的使用都不熟,由于工作需要经常需要在github上pull request,第一次还是有些麻烦的,写个笔记记录下 1. fork源项目到自己的github仓库中 fork之后自己也会多出一 ...