【洛谷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 洛谷 ...
随机推荐
- 虚拟机CentOS克隆
1.什么是克隆 就是以某虚拟机为母版,复制出一个一模一样的虚拟机出来,包括里面的数据 2.创建克隆 正常选择通过快照创建克隆(只能是关机状态下的克隆) 1.选择关机状态下的快照,然后点击克隆 2.点击 ...
- kali更新软件源
首先就是修改软件源文件 /etc/apt/sources.list 可以用leafpad打开,在终端中键入: leafpad /etc/apt/sources.list 原码是kali官方的软件源,更 ...
- 2. 运行Spark Streaming
2.1 IDEA编写程序 Pom.xml加入以下依赖: <dependency> <groupId>org.apache.spark</groupId> <a ...
- bootstrap-paginator + ajax 实现动态翻页功能
1.下载http://plugins.jquery.com/bootstrap-paginator/ 2.引用<script src="/static/bootstrap/js/boo ...
- Golang ---基准测试
什么是基准测试 基准测试,是一种测试代码性能的方法,比如你有多种不同的方案,都可以解决问题,那么到底是那种方案性能更好呢?这时候基准测试就派上用场了. 基准测试主要是通过测试CPU和内存的效率问题,来 ...
- 全栈项目|小书架|服务器端-NodeJS+Koa2实现首页图书列表接口
通过上篇文章 全栈项目|小书架|微信小程序-首页水平轮播实现 我们实现了前端(小程序)效果图的展示,这篇文章来介绍服务器端的实现. 首页书籍信息 先来回顾一下首页书籍都有哪些信息: 从下面的图片可以看 ...
- Chrome 谷歌开发者工具使用窍门
我们这里介绍主要的几块:Console.Source.Network Console 大家都有用过各种类型的浏览器,每种浏览器都有自己的特色,本人拙见,在我用过的浏览器当中,我是最喜欢Chrome的, ...
- Spring-Cloud之Eureka注册与发现-2
一.Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的.SpringCloud将它集成在其 ...
- IQueryable,IEnumerable,IList区别
IQueryable和IEnumerable都是延时执行(Deferred Execution)的,而IList是即时执行(Eager Execution)IQueryable和IEnumerable ...
- java之mybatis之占位符
1.mybatis中有两种占位符 #{}和 ${}. 2. #{} 占位符是为了获取值,获取的值用在 where 语句后,insert 语句后,update 语句. #{} 获取值,是根据值的名称取值 ...