【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 & ...
随机推荐
- H5 表单标签
33-表单标签3 列表数据 注意点: 1.下拉列表不能输入内容, 但是可以直接在列表中选择内容 2.可以通过给option标签添加一个selected属性来指定列表的默认值 3.可以通过给option ...
- Array Queries CodeForces - 797E
题目链接 非常好的一道题目, 分析,如果用暴力的话,时间复杂度是O(q*n)稳稳的超时 如果用二维DP的话,需要O (n*n)的空间复杂度,会爆空间. 那么分析一下,如果k>sqrt(n)的话, ...
- Mysql 索引问题集锦
一.Mysql 中的索引 索引:顾名思义用来检索.查找数据的key (字段) 几种Mysql 中的常见索引分类:普通索引(联合索引).唯一索引.主键索引.全文索引 优点:使得查询数据变快 缺点:更新数 ...
- Python_内置函数之round的幺蛾子
pycharm运行结果 1 ret = round(0.5) print(ret) >>> 0 ret1 = round(1.5) print(ret1) >>> ...
- 使用log4j记录日志
目录 log4j的优点 导入log4j的jar包 log4j的错误级别 log4j日志的输出目的地 log4j的配置示例 log4j的全局配置讲解 控制台日志的配置讲解 日志输出文件的配置讲解 使用l ...
- Linux 典型应用之常用命令
软件操作相关命令 软件包管理 (yum) 安装软件 yum install xxx(软件的名字) 如 yum install vim 卸载软件 yum remove xxx(软件的名字) 如 yum ...
- php开发之系统函数
一些常用的php开发之系统函数的使用,可以使我们的开发效率,事倍功半 1) BC高精度函数库 2)
- JMeter中返回Json数据的处理方法(转)
Json 作为一种数据交换格式在网络开发,特别是 Ajax 与 Restful 架构中应用的越来越广泛.而 Apache 的 JMeter 也是较受欢迎的压力测试工具之一,但是它本身没有提供对于 Js ...
- [FreeBuff]Trojan.Miner.gbq挖矿病毒分析报告
Trojan.Miner.gbq挖矿病毒分析报告 https://www.freebuf.com/articles/network/196594.html 竟然还有端口转发... 这哥们.. 江民安全 ...
- 【转】 Golang输入输出格式化Printf Springf Fprintf..
// Go 在传统的`printf` 中对字符串格式化提供了优异的支持. // 这里是一些基本的字符串格式化的人物的例子. package main import "fmt" im ...