【XSY2528】道路建设 LCT 可持久化线段树
题目描述
给你一个\(n\)个点\(m\)条边图,\(q\)个询问,每次问你边权在\([l,r]\)之间的边组成的最小生成树(森林)的边权和。强制在线。
\(n,m,q\leq 100000\)
题解
考虑离线做法。从大到小加边,用LCT维护当前的最小生成树。维护一棵线段树,第\(i\)个位置表示当前的最小生成树中边权为\(i\)的边的权值和。当一条边被加入时就在对应位置加上边权,删掉时就减掉边权。假设已经处理了边权\(\geq i\)的所有边,那么对于所有\(l=i\)的询问的答案就是线段树中\([1,r]\)的数和(等价于\([l,r]\),因为\([1,l-1]\)都是空的)。
把这棵线段树变成可持久化线段树就可以在线处理询问了。
我也不知道为什么边权范围是\([1,10000]\)。
时间复杂度:\(O((m+q)\log n)\)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
namespace lct
{
int f[200010];
int a[200010][2];
pii s[200010];
pii v[200010];
int rev[200010];
void reverse(int x)
{
rev[x]^=1;
swap(a[x][0],a[x][1]);
}
void push(int x)
{
if(rev[x])
{
if(a[x][0])
reverse(a[x][0]);
if(a[x][1])
reverse(a[x][1]);
rev[x]=0;
}
}
void mt(int x)
{
s[x]=v[x];
if(a[x][0])
s[x]=max(s[x],s[a[x][0]]);
if(a[x][1])
s[x]=max(s[x],s[a[x][1]]);
}
int root(int x)
{
return !f[x]||(a[f[x]][0]!=x&&a[f[x]][1]!=x);
}
void rotate(int x)
{
if(root(x))
return;
int p=f[x];
int q=f[p];
int ps=(x==a[p][1]);
int qs=(p==a[q][1]);
int ch=a[x][ps^1];
if(!root(p))
a[q][qs]=x;
a[x][ps^1]=p;
a[p][ps]=ch;
if(ch)
f[ch]=p;
f[p]=x;
f[x]=q;
mt(p);
mt(x);
}
void pushdown(int x)
{
if(!root(x))
pushdown(f[x]);
push(x);
}
void splay(int x)
{
pushdown(x);
while(!root(x))
{
int p=f[x];
if(!root(p))
{
int q=f[p];
if((x==a[p][1])^(p==a[q][1]))
rotate(x);
else
rotate(p);
}
rotate(x);
}
}
void access(int x)
{
int y=x,t=0;
while(x)
{
splay(x);
a[x][1]=t;
mt(x);
t=x;
x=f[x];
}
splay(y);
}
void change(int x)
{
access(x);
reverse(x);
}
void link(int x,int y)
{
change(x);
f[x]=y;
}
void cut(int x,int y)
{
change(x);
access(y);
f[a[y][0]]=0;
a[y][0]=0;
}
pii query(int x,int y)
{
change(x);
access(y);
return s[y];
}
int findroot(int x)
{
access(x);
while(a[x][0])
x=a[x][0];
splay(x);
return x;
}
}
namespace seg
{
int n=0;
int ls[5000010];
int rs[5000010];
int s[5000010];
int rt[100010];
int change(int p1,int x,int v,int l,int r)
{
int p=++n;
ls[p]=ls[p1];
rs[p]=rs[p1];
s[p]=s[p1]+v;
if(l==r)
return p;
int mid=(l+r)>>1;
if(x<=mid)
ls[p]=change(ls[p1],x,v,l,mid);
if(x>mid)
rs[p]=change(rs[p1],x,v,mid+1,r);
return p;
}
int query(int p,int l,int r,int L,int R)
{
if(l<=L&&r>=R)
return s[p];
int mid=(L+R)>>1;
int res=0;
if(l<=mid)
res+=query(ls[p],l,r,L,mid);
if(r>mid)
res+=query(rs[p],l,r,mid+1,R);
return res;
}
}
struct edge
{
int x,y,d;
};
int cmp(edge a,edge b)
{
return a.d<b.d;
}
edge a[100010];
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
int n,m,on;
scanf("%d%d%d",&n,&m,&on);
int i;
for(i=1;i<=m;i++)
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].d);
sort(a+1,a+m+1,cmp);
int j=m;
seg::rt[n+1]=0;
for(i=1;i<=n;i++)
lct::v[i]=pii(0,0);
for(i=10000;i>=1;i--)
{
seg::rt[i]=seg::rt[i+1];
while(j>=1&&a[j].d==i)
{
int rx=lct::findroot(a[j].x);
int ry=lct::findroot(a[j].y);
if(rx==ry)
{
pii s=lct::query(a[j].x,a[j].y);
if(s.first>a[j].d)
{
lct::cut(a[s.second].x,s.second+n);
lct::cut(a[s.second].y,s.second+n);
lct::v[j+n]=pii(a[j].d,j);
lct::link(a[j].x,j+n);
lct::link(a[j].y,j+n);
seg::rt[i]=seg::change(seg::rt[i],s.first,-s.first,1,10000);
seg::rt[i]=seg::change(seg::rt[i],a[j].d,a[j].d,1,10000);
}
}
else
{
lct::v[j+n]=pii(a[j].d,j);
lct::link(a[j].x,j+n);
lct::link(a[j].y,j+n);
seg::rt[i]=seg::change(seg::rt[i],a[j].d,a[j].d,1,10000);
}
j--;
}
}
int q;
scanf("%d",&q);
int l,h,last=0;
for(i=1;i<=q;i++)
{
scanf("%d%d",&l,&h);
l-=on*last;
h-=on*last;
last=seg::query(seg::rt[l],1,h,1,10000);
printf("%d\n",last);
}
return 0;
}
【XSY2528】道路建设 LCT 可持久化线段树的更多相关文章
- 【bzoj3514】Codechef MARCH14 GERALD07加强版 LCT+可持久化线段树
题目描述 N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. 输入 第一行四个整数N.M.K.type,代表点数.边数.询问数以及询问是否加密.接下来M行,代表图中的每条边 ...
- bzoj 3514: GERALD07加强版 lct+可持久化线段树
题目大意: N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. 题解: 这道题考试的时候没想出来 于是便爆炸了 结果今天下午拿出昨天准备的题表准备做题的时候 题表里就有这题 ...
- BZOJ3514 Codechef MARCH14 GERALD07加强版 LCT+可持久化线段树
自己独自想出来并切掉还是很开心的~ Code: #include <bits/stdc++.h> #define N 400005 #define inf 1000000000 #defi ...
- HDU 5820 (可持久化线段树)
Problem Lights (HDU 5820) 题目大意 在一个大小为50000*50000的矩形中,有n个路灯.(n<=500000) 询问是否每一对路灯之间存在一条道路,使得长度为|x1 ...
- 【BZOJ4704】旅行 树链剖分+可持久化线段树
[BZOJ4704]旅行 Description 在Berland,有n个城堡.每个城堡恰好属于一个领主.不同的城堡属于不同的领主.在所有领主中有一个是国王,其他的每个领主都直接隶属于另一位领主,并且 ...
- PYOJ 44. 【HNSDFZ2016 #6】可持久化线段树
#44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...
- 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集
3673: 可持久化并查集 by zky Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 1878 Solved: 846[Submit][Status ...
- 【BZOJ-2653】middle 可持久化线段树 + 二分
2653: middle Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1298 Solved: 734[Submit][Status][Discu ...
- HDU 4866 Shooting(持久化线段树)
view code//第二道持久化线段树,照着别人的代码慢慢敲,还是有点不理解 #include <iostream> #include <cstdio> #include & ...
随机推荐
- FreeBSD常用操作
导读 最近遇到一些FreeBSD的故障,在这种操作系统上我们平时用的一些命令无法执行,FreeBSD的一些配置文件也和其他很多Linux系统不一样.为了方便以后查阅,我特别整理了这篇文档. 1. 网络 ...
- pip3 升级失败的解决方法!亲测有效
pip3 --default-timeout=10000 install -U pip 注意:由于防火长城的存在,会导致更新失败,如果你加上--default-timeout=10000 这个就ok ...
- RabbitMQ消息的交换
消息的交换 目录 RabbitMQ-从基础到实战(1)— Hello RabbitMQ RabbitMQ-从基础到实战(2)— 防止消息丢失 1.简介 在前面的例子中,每个消息都只对应一个消费者,即使 ...
- asp.net mvc Areas 母版页动态获取数据进行渲染
经常需要将一些通用的页面元素抽离出来制作成母版页,但是这里的元素一般都是些基本元素,即不需要 进行后台数据交换的基本数据,但是对于一些需要通过后台查询的数据,我们应该怎么传递给前台的母版页呢 这里描述 ...
- JMeter中返回Json数据的处理方法(转)
Json 作为一种数据交换格式在网络开发,特别是 Ajax 与 Restful 架构中应用的越来越广泛.而 Apache 的 JMeter 也是较受欢迎的压力测试工具之一,但是它本身没有提供对于 Js ...
- C#设计模式之9:模板方法
模板方法 模板方法是一个方法,定义了算法的步骤,并允许子类为一个或多个步骤提供实现. 本例中用冲泡咖啡和茶的例子来说明: 上图说明了冲泡咖啡和茶的步骤,可以看出冲泡咖啡和茶的步骤差不多,很相似,先来看 ...
- Vagrant系列(二)----Vagrant的配置文件Vagrantfile详解
一.简介 在我们的工作目录下有一个Vagrantfile文件,里面包含有大量的配置信息,通过它可以定义虚拟机的各种配置,如网络.内存.主机名等,主要包括三个方面的配置,虚拟机的配置.SSH配置.Vag ...
- getMessage(),getFile,getLine获取异常用法
try { $param = $request->all(); $param['building_id'] = 0; $param['sync'] = 2; // 1小程序2App $param ...
- C# Note20: 制作延时改变显示的标题栏
前言 在使用wpf构建一个窗体时,其中有这样一个功能,在保存数据或加载数据时,我们希望在改变标题栏的显示以标志当前保存成功的状态或者加载数据的名称信息,而且标题信息更新显示几秒后,再恢复到默认的状态. ...
- 【gedit】 显示行号
打开gedit文本编辑器->Edit(编辑)->preferences(预设)->view(视图)->在Display line numbers前打勾->close