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

如果正常动态维护最大生成树的话用 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. Kibana访问报错

    浏览器访问提示:Kibana server is not ready yet 查看日志如下 {"type":"log","@timestamp&quo ...

  2. busybox测试dns问题

    获取svc [root@master01 ~]# kubectl get svc NAME                 TYPE        CLUSTER-IP       EXTERNAL- ...

  3. 使用Dapper查询记录是否存在

    /// <summary> /// Dapper数据访问抽象基础类 /// </summary> public class DapperHelper { public stat ...

  4. 两台Windows的 IIS 应用站点 基于NLB + ARR 实现双机热备和负载

    IIS负载均衡中我们使用微软的ARR,但提到网站的高可用性,ARR只能做请求入口的消息分发服务,这样如果我们的消息分发服务器给down掉啦,那么做再多的应用服务集群也都枉然. 这里我们主要针对解决这一 ...

  5. MVC学习笔记(一)—用EF创建数据库

    1.新建MVC项目     2.在Models文件夹下添加名为User的新类   2.1 Users类中的代码为: public class Users { /// <summary> / ...

  6. vue创建项目(推荐)

    上一节我们介绍了vue搭建环境的情况,并使用一种方式搭建了一个项目,在这里为大家推荐另一种创建项目的方式. vue init webpack-simple vuedemo02 cd vuedemo02 ...

  7. 创建图 figure & figcaption

    如报纸.杂志.报告等其他媒介上看到过图.通常,图是由页面上的文本引述出. 在HTML5出现之前,没有专门实现这个目的的元素,因此一些开发人员想出了他们自己的解决办法(通常会使用不那么理想的.没有语义的 ...

  8. react native 集成react navigation报错

    集成后出现:“Invalid escape sequence at line 1 column 29 path $[0].name”的错误. 解决办法:

  9. ETC1/DXT1 compressed textures are not supported when publishing to iPhone

    Build application in Unity 2017.20f3 用Unity2017/2018编译iPhone版本出现以下错误: ETC1(or DXT1) compressed textu ...

  10. WPF 依赖属性前言

    WPF 依赖属性前言 ​ 在.net中,我们可以属性来获取或设置字段的值,不需要在编写额外的get和set方法,但这有一个前提,那就是需要在对象中拥有一个字段,才能在此字段的基础上获取或设置字段的值, ...