【洛谷P4319】 变化的道路 线段树分治+LCT
最近学了一下线段树分治,感觉还蛮好用...
如果正常动态维护最大生成树的话用 LCT 就行,但是这里还有时间这一维的限制.
所以,我们就把每条边放到以时间为轴的线段树的节点上,然后写一个可撤销 LCT 就好了 ~
code:
#include <bits/stdc++.h>
#define RM 32766
#define N 2000005
#define ll long long
#define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)
using namespace std;
namespace LCT
{
#define lson t[x].ch[0]
#define rson t[x].ch[1]
struct node
{
ll sum;
int f,ch[2],rev,w,maxx,id;
}t[N];
int sta[N];
inline int get(int x) { return t[t[x].f].ch[1]==x; }
inline int Irt(int x) { return !(t[t[x].f].ch[0]==x||t[t[x].f].ch[1]==x); }
inline void mark(int x)
{
if(!x) return;
swap(lson,rson), t[x].rev^=1;
}
inline void pushdown(int x)
{
if(x&&t[x].rev)
{
if(lson) mark(lson);
if(rson) mark(rson);
t[x].rev=0;
}
}
inline void pushup(int x)
{
t[x].id=x;
t[x].sum=t[x].w;
t[x].maxx=t[x].w;
if(lson)
{
t[x].sum+=t[lson].sum;
if(t[lson].maxx>t[x].maxx)
{
t[x].id=t[lson].id;
t[x].maxx=t[lson].maxx;
}
}
if(rson)
{
t[x].sum+=t[rson].sum;
if(t[rson].maxx>t[x].maxx)
{
t[x].id=t[rson].id;
t[x].maxx=t[rson].maxx;
}
}
}
inline void rotate(int x)
{
int old=t[x].f,fold=t[old].f,which=get(x);
if(!Irt(old)) t[fold].ch[t[fold].ch[1]==old]=x;
t[old].ch[which]=t[x].ch[which^1], t[t[old].ch[which]].f=old;
t[x].ch[which^1]=old,t[old].f=x,t[x].f=fold;
pushup(old), pushup(x);
}
inline void splay(int x)
{
int u=x,v=0,fa;
for(sta[++v]=u;!Irt(u);u=t[u].f) sta[++v]=t[u].f;
for(;v;--v) pushdown(sta[v]);
for(u=t[u].f;(fa=t[x].f)!=u;rotate(x)) if(t[fa].f!=u) rotate(get(fa)==get(x)?fa:x);
}
inline void Access(int x)
{
for(int y=0;x;y=x,x=t[x].f) splay(x),rson=y,pushup(x);
}
inline void MakeRT(int x)
{
Access(x),splay(x),mark(x);
}
inline void Link(int x,int y)
{
MakeRT(y),t[y].f=x;
}
inline void split(int x,int y)
{
MakeRT(x),Access(y),splay(y);
}
inline void cut(int x,int y)
{
MakeRT(y),Access(x),splay(x);
t[x].ch[0]=t[y].f=0;
pushup(x);
}
inline int findroot(int x)
{
for(Access(x),splay(x);lson;x=lson);
return x;
}
#undef lson
#undef rson
};
#define lson now<<1
#define rson now<<1|1
int n;
int tag[N];
vector<int>G[N<<2];
struct edge
{
int u,v,w;
edge(int u=0,int v=0,int w=0):u(u),v(v),w(w){}
}e[N];
struct E
{
int u,op;
E(int u=0,int op=0):u(u),op(op){}
};
void Modify(int l,int r,int now,int L,int R,int id)
{
if(l>=L&&r<=R)
{
G[now].push_back(id);
return;
}
int mid=(l+r)>>1;
if(L<=mid) Modify(l,mid,lson,L,R,id);
if(R>mid) Modify(mid+1,r,rson,L,R,id);
}
void solve(int l,int r,int now,ll pre)
{
stack<E>S;
for(int i=0;i<G[now].size();++i)
{
int id=G[now][i];
int u=e[id].u,v=e[id].v,w=e[id].w;
int _new=id+n;
if(LCT::findroot(u)!=LCT::findroot(v))
{
LCT::t[_new].w=w;
LCT::Link(u,_new);
LCT::Link(_new,v);
pre+=1ll*w;
S.push(E(_new,0));
}
else
{
LCT::split(u,v);
if(LCT::t[v].maxx>w)
{
pre=pre-LCT::t[v].maxx+w;
int tmp=LCT::t[v].id;
LCT::cut(tmp,e[tmp-n].u);
LCT::cut(tmp,e[tmp-n].v);
LCT::t[_new].w=w;
LCT::Link(u,_new);
LCT::Link(_new,v);
S.push(E(tmp,1));
S.push(E(_new,0));
}
}
}
if(l==r) printf("%lld\n",pre+1);
else
{
int mid=(l+r)>>1;
if(l<=mid) solve(l,mid,lson,pre);
if(r>mid) solve(mid+1,r,rson,pre);
}
while(!S.empty())
{
E pp=S.top(); S.pop();
if(pp.op==0)
{
LCT::cut(pp.u,e[pp.u-n].u);
LCT::cut(pp.u,e[pp.u-n].v);
}
else
{
LCT::t[pp.u].w=e[pp.u-n].w;
LCT::Link(pp.u,e[pp.u-n].u);
LCT::Link(pp.u,e[pp.u-n].v);
}
}
}
#undef lson
#undef rson
int main()
{
// setIO("input");
int i,j,m;
scanf("%d",&n);
for(i=1;i<n;++i)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
e[i]=edge(u,v,w);
Modify(1,RM,1,1,RM,i);
}
scanf("%d",&m);
for(i=1;i<=m;++i)
{
int u,v,w,l,r;
scanf("%d%d%d%d%d",&u,&v,&w,&l,&r), e[n+i-1]=edge(u,v,w), Modify(1,RM,1,l,r,n+i-1);
}
solve(1,RM,1,0ll);
return 0;
}
【洛谷P4319】 变化的道路 线段树分治+LCT的更多相关文章
- 洛谷P4319 变化的道路
题意:给定图,每条边都有一段存在时间.求每段时间的最小生成树. 解:动态MST什么毒瘤...洛谷上还是蓝题... 线段树分治 + lct维护最小生成树. 对时间开线段树,每条边的存在时间在上面会对应到 ...
- 洛谷 P4319 变化的道路 解题报告
P4319 变化的道路 题目描述 小 w 和小 c 在 H 国,近年来,随着 H 国的发展,H 国的道路也在不断变化着 根据 H 国的道路法,H 国道路都有一个值 \(w\),表示如果小 w 和小 c ...
- 【刷题】洛谷 P4319 变化的道路
题目描述 小 w 和小 c 在 H 国,近年来,随着 H 国的发展,H 国的道路也在不断变化着 根据 H 国的道路法,H 国道路都有一个值 \(w\) ,表示如果小 w 和小 c 通过这条道路,那么他 ...
- 洛谷 P2147 [SDOI2008]洞穴勘测 (线段树分治)
题目链接 题解 早就想写线段树分治的题了. 对于每条边,它存在于一段时间 我们按时间来搞 我们可把一条边看做一条线段 我们可以模拟线段树操作,不断分治下去 把覆盖\(l-r\)这段时间的线段筛选出来, ...
- 洛谷 P3373 【模板】线段树 2
洛谷 P3373 [模板]线段树 2 洛谷传送门 题目描述 如题,已知一个数列,你需要进行下面三种操作: 将某区间每一个数乘上 xx 将某区间每一个数加上 xx 求出某区间每一个数的和 输入格式 第一 ...
- BZOJ2001 HNOI2010城市建设(线段树分治+LCT)
一个很显然的思路是把边按时间段拆开线段树分治一下,用lct维护MST.理论上复杂度是O((M+Q)logNlogQ),实际常数爆炸T成狗.正解写不动了. #include<iostream> ...
- bzoj 4025 二分图——线段树分治+LCT
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4025 线段树分治,用 LCT 维护链的长度即可.不过很慢. 正常(更快)的方法应该是线段树分 ...
- P3206 [HNOI2010]城市建设 [线段树分治+LCT维护动态MST]
Problem 这题呢 就边权会在某一时刻变掉-众所周知LCT不支持删边的qwq- 所以考虑线段树分治- 直接码一发 如果 R+1 这个时间修改 那就当做 [L,R] 插入了一条边- 然后删的边和加的 ...
- 洛谷P3372 【模板】线段树 1
P3372 [模板]线段树 1 153通过 525提交 题目提供者HansBug 标签 难度普及+/提高 提交 讨论 题解 最新讨论 [模板]线段树1(AAAAAAAAA- [模板]线段树1 洛谷 ...
随机推荐
- Mysql批量更新的三种方式
前言 批量插入由于mysql的VALUES原生支持,使用较为便利. 批量更新的写法一般有三种,在更新数量较少的情况下,前两种性能不相上下.但是在更新字段增加,更新条数较多(500以上)建议使用第三种写 ...
- ELK +Nlog 分布式日志系统的搭建 For Windows
前言 我们为啥需要全文搜索 首先,我们来列举一下关系型数据库中的几种模糊查询 MySql : 一般情况下LIKE 模糊查询 SELECT * FROM `LhzxUsers` WHERE UserN ...
- Python进阶----数据库的基础,关系型数据库与非关系型数据库(No SQL:not only sql),mysql数据库语言基础(增删改查,权限设定)
day37 一丶Python进阶----数据库的基础,mysql数据库语言基础(增删改查,权限设定) 什么是数据库: 简称:DataBase ---->DB 数据库即存放数据的仓库, ...
- 英伟达 cuda 开发套件下载
下载地址 https://developer.nvidia.com/cuda-toolkit 安装比较简单,就不多说了.
- pandas-04 多级index操作
pandas-04 多级index操作 在pandas中可以为series和dataframe设置多个index,也就是说可以有多级index和column.这样可以对pandas的操作更加灵活. i ...
- k8s日志收集及存档
k8s日志收集架构图 利用阿里开源的工具log-pilot,往kafka内写日志,然后吐一份至es,另外一份用flume消费kafka数据落盘
- 令人兴奋的TOP Server OPC Server v6.5 五大功能(上)
Software Toolbox的OPC和原生HMI设备的连接软件:TOP Server OPC Server.TOP Server OPC Server是采用业界领先的Kepware技术的工业4.0 ...
- MySQL NULL--三值逻辑(Three Value Logic)
三值逻辑(Three Value Logic) 在关系型数据库中,由于NULL值的存在,导致逻辑表达式存在三种值:TRUE/FALSE/UNKNOW. SELECT '=NULL AS C1, ' A ...
- git指令集合
原网页:https://www.linuxidc.com/Linux/2018-04/151809.htm Git 是一个很强大的分布式版本控制系统.它不但适用于管理大型开源软件的源代码,管理私人的文 ...
- django中使用AJAX时如何获取表单参数(按钮携带参数)
前提是函数和相应的视图路由都已经配置好了,然后就是表单了: <form id="SmsForm" method="post" class="a& ...