【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 & ...
随机推荐
- React-redux框架之connect()与Provider组件 用法讲解
react-redux 在react-redux 框架中,给我提供了两个常用的API来配合Redux框架的使用,其实在我们的实际项目开发中,我们完全可以不用react-redux框架,但是如果使用此框 ...
- mysql有多大内存?能存多少数据?
Mysql: MySQL 3.22 限制的表大小为4GB. MyISAM 存储引擎: 最大表尺寸增加到了65536TB(2567 – 1字节).由于允许的表尺寸更大,MySQL数据库的最大有效表尺寸通 ...
- C# List用法 List介绍
一.#List泛型集合 集合是OOP中的一个重要概念,C#中对集合的全面支持更是该语言的精华之一. 为什么要用泛型集合? 在C# 2.0之前,主要可以通过两种方式实现集合: a.使用ArrayList ...
- 学习笔记:filter_var()函数
PHP 过滤器用于对来自非安全来源的数据(比如用户输入)进行验证和过滤 filter_var() 函数通过指定的过滤器过滤变量. 如果成功,则返回已过滤的数据,如果失败,则返回 false. 语法 f ...
- Oracle行列转换case when then方法案例
select (select name from t_area where id=areaid) 区域, end) 一月, end) 二月, end) 三月, end) 四月, end) 五月, en ...
- vue页面是否缓存的两种方式
第一种 <keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> ...
- Codeforces 1154F Shovels Shop
题目链接:http://codeforces.com/problemset/problem/1154/F 题目大意: 商店有n把铲子,欲购k把,现有m种优惠,每种优惠可使用多次,每种优惠(x, y)表 ...
- Java中 VO、 PO、DO、DTO、 BO、 QO、DAO、POJO的概念(转)
PO(persistant object) 持久对象 在 o/r 映射的时候出现的概念,如果没有 o/r 映射,没有这个概念存在了.通常对应数据模型 ( 数据库 ), 本身还有部分业务逻辑的处理.可以 ...
- Helm
helm类似yum helm下载的是配置清单文件 核心术语: Chart:一个helm程序包: Repository:Charts仓库,https/http服务器: Release:特定的Chart部 ...
- 如何在网页中用echarts图表插件做出静态呈现效果
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...