【题解】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 ...
随机推荐
- css学习_css补充知识
1.渐进增强,优雅降级 2.浏览器前缀 3.背景渐变 4.css 验证工具 2种方式:第2种支持验证本地的css(推荐) 5.css压缩 ----(节约空间,节省带宽) 6.旋转轮播图 案例: ...
- php中数组直接用加号相加array+array
php中数组功能非常强大,甚至也可以直接通过+相加来合并数组. A数组 $a = ['a', 'b']; B数组 $b = ['c', 'd', 'e']; A+B结果 Array ( [0] =&g ...
- Xcode工程编译错误之iOS开发之The Xcode build system has crashed. Please close and reopen your workspace
解决方法: . 删除DerivedData . 参照上面的链接设置:File -> Workspace Settings -> Build System -> Legacy Buil ...
- oracle初级语法
--select关键字第一个句型: select emp.ename,emp.sal from emp; --from 关键字后面跟 需要查询表名: select ename from emp; -- ...
- UnicodeDecodeError: 'ascii' codec can't decode byte 0xc7 in position 20: ordinal not in range(128)
dict = pickle.load(open(file, 'rb')) 修改为: dict = pickle.load(open(file, 'rb'), encoding='iso-8859-1' ...
- java手写线程池,完善中
package com.test001.threadpool; import java.util.LinkedList; import java.util.List; import java.util ...
- MySQL 基础 查询
别名 查询数据时,如果表名很长,使用起来不方便,此时,就可以为表取一个别名,用这个别名来代替表的名称 .同时为了更好的显示所查询出来的字段,也可以给字段取别名. 一,表作为别名: mysql> ...
- 杂记:解决Android扫描BLE设备名称不刷新问题
背景 个人开发过一种BLE设备有这样一种需求:当设备处于状态A时,广播设备名称A:处于状态B时,广播设备名称B. 问题 我们发现,当Android在进行Ble扫描的时候,扫描回调函数onScanRes ...
- ios sdk 配置路径
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport command+shift + ...
- JDBCUtils相关
1.之所以使用类加载器InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbcInfo.prop ...