最近学了一下线段树分治,感觉还蛮好用...

如果正常动态维护最大生成树的话用 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的更多相关文章

  1. 洛谷P4319 变化的道路

    题意:给定图,每条边都有一段存在时间.求每段时间的最小生成树. 解:动态MST什么毒瘤...洛谷上还是蓝题... 线段树分治 + lct维护最小生成树. 对时间开线段树,每条边的存在时间在上面会对应到 ...

  2. 洛谷 P4319 变化的道路 解题报告

    P4319 变化的道路 题目描述 小 w 和小 c 在 H 国,近年来,随着 H 国的发展,H 国的道路也在不断变化着 根据 H 国的道路法,H 国道路都有一个值 \(w\),表示如果小 w 和小 c ...

  3. 【刷题】洛谷 P4319 变化的道路

    题目描述 小 w 和小 c 在 H 国,近年来,随着 H 国的发展,H 国的道路也在不断变化着 根据 H 国的道路法,H 国道路都有一个值 \(w\) ,表示如果小 w 和小 c 通过这条道路,那么他 ...

  4. 洛谷 P2147 [SDOI2008]洞穴勘测 (线段树分治)

    题目链接 题解 早就想写线段树分治的题了. 对于每条边,它存在于一段时间 我们按时间来搞 我们可把一条边看做一条线段 我们可以模拟线段树操作,不断分治下去 把覆盖\(l-r\)这段时间的线段筛选出来, ...

  5. 洛谷 P3373 【模板】线段树 2

    洛谷 P3373 [模板]线段树 2 洛谷传送门 题目描述 如题,已知一个数列,你需要进行下面三种操作: 将某区间每一个数乘上 xx 将某区间每一个数加上 xx 求出某区间每一个数的和 输入格式 第一 ...

  6. BZOJ2001 HNOI2010城市建设(线段树分治+LCT)

    一个很显然的思路是把边按时间段拆开线段树分治一下,用lct维护MST.理论上复杂度是O((M+Q)logNlogQ),实际常数爆炸T成狗.正解写不动了. #include<iostream> ...

  7. bzoj 4025 二分图——线段树分治+LCT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4025 线段树分治,用 LCT 维护链的长度即可.不过很慢. 正常(更快)的方法应该是线段树分 ...

  8. P3206 [HNOI2010]城市建设 [线段树分治+LCT维护动态MST]

    Problem 这题呢 就边权会在某一时刻变掉-众所周知LCT不支持删边的qwq- 所以考虑线段树分治- 直接码一发 如果 R+1 这个时间修改 那就当做 [L,R] 插入了一条边- 然后删的边和加的 ...

  9. 洛谷P3372 【模板】线段树 1

    P3372 [模板]线段树 1 153通过 525提交 题目提供者HansBug 标签 难度普及+/提高 提交  讨论  题解 最新讨论 [模板]线段树1(AAAAAAAAA- [模板]线段树1 洛谷 ...

随机推荐

  1. C++错题记录

    D. 通俗讲 , 前置++ : 先自增,再赋值    后置++: 先赋值,再自增 从反汇编中,可以看出: 前置++效率比后置++高 前置++: 自增后返回引用   后置++: 拷贝一份临时变量,再自增 ...

  2. antd通过 filterDropdown 自定义--按某天时间搜索

    import React, { Component } from 'react'; import { Table, Input, Button, Icon, DatePicker } from 'an ...

  3. java之spring mvc之helloworld

    这篇主要讲解springmvc的基本的使用,这里以helloworld项目为例. 目录结构: 1. 新建 web 项目 :springmvc_helloworld 2. 在 WebRoot\WEB-I ...

  4. vue中is与:is的区别

    简略回答 假设父组件中有一个show数据,show="one":is="show"-->实际上是is="one" is="s ...

  5. getElementsByClassName兼容 封装

    众所周知,JS获取DOM有个getElementsByClassName,非常方便,但是呢,为了兼容某些浏览器(你懂的).只能 进行封装下了.解决方法如下 <!DOCTYPE html> ...

  6. Nginx配置Yii:backend&frontend

    #My vlson.top project #frontend server { listen 80; server_name www.vlson.com; #charset koi8-r; set ...

  7. KVM on CubieTruck 原理以及网络性能相关思考

    1.virtio框架包括哪些? (1)virtio:面向guest驱动的API接口,它在概念上将前端驱动附加到后端驱动,具体实现位于driver/virtio/virtio.c (2)Transpor ...

  8. 图说jdk1.8新特性(1)--- 函数式接口

    函数式接口 总结起来就以下几点: 如果一个接口要想成为函数接口(函数接口可以直接用lambda方式简化),则必须有且仅有一个抽象的方法(非default和static) 可以通过注解@Function ...

  9. Java字符串操作工具类

    import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.lang. ...

  10. CASE WHEN 函数

    --Case函数: --有两种格式: -- 1.简单Case函数. -- 2.Case搜索函数. --1.简单Case函数: -- CASE [COLUMN_NAME] -- WHEN ['条件参数' ...