【XSY2528】道路建设 LCT 可持久化线段树

时间:2022-09-16 23:43:09

题目描述

  给你一个\(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 可持久化线段树的更多相关文章

  1. 【bzoj3514】Codechef MARCH14 GERALD07加强版 LCT&plus;可持久化线段树

    题目描述 N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. 输入 第一行四个整数N.M.K.type,代表点数.边数.询问数以及询问是否加密.接下来M行,代表图中的每条边 ...

  2. bzoj 3514&colon; GERALD07加强版 lct&plus;可持久化线段树

    题目大意: N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. 题解: 这道题考试的时候没想出来 于是便爆炸了 结果今天下午拿出昨天准备的题表准备做题的时候 题表里就有这题 ...

  3. BZOJ3514 Codechef MARCH14 GERALD07加强版 LCT&plus;可持久化线段树

    自己独自想出来并切掉还是很开心的~ Code: #include <bits/stdc++.h> #define N 400005 #define inf 1000000000 #defi ...

  4. HDU 5820 &lpar;可持久化线段树)

    Problem Lights (HDU 5820) 题目大意 在一个大小为50000*50000的矩形中,有n个路灯.(n<=500000) 询问是否每一对路灯之间存在一条道路,使得长度为|x1 ...

  5. 【BZOJ4704】旅行 树链剖分&plus;可持久化线段树

    [BZOJ4704]旅行 Description 在Berland,有n个城堡.每个城堡恰好属于一个领主.不同的城堡属于不同的领主.在所有领主中有一个是国王,其他的每个领主都直接隶属于另一位领主,并且 ...

  6. PYOJ 44&period; 【HNSDFZ2016 &num;6】可持久化线段树

    #44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...

  7. 【BZOJ-3673&amp&semi;3674】可持久化并查集 可持久化线段树 &plus; 并查集

    3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status ...

  8. 【BZOJ-2653】middle 可持久化线段树 &plus; 二分

    2653: middle Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1298  Solved: 734[Submit][Status][Discu ...

  9. HDU 4866 Shooting&lpar;持久化线段树&rpar;

    view code//第二道持久化线段树,照着别人的代码慢慢敲,还是有点不理解 #include <iostream> #include <cstdio> #include & ...

随机推荐

  1. FreeCAD鼠标操作指南

    鼠标控制模式 跳转至: 导航. 搜索 freeCAD鼠标的控制模式由多个命令构成,用于三维空间的视觉导航和控制显示对象.freecad支持多个鼠标导航方式.默认的导航方式是被称为“CAD导航”,非常简 ...

  2. JSP通过IP获取用户(客户端)的地理位置信息

    <%!//获取客户端的IP public String getRemoteIP(HttpServletRequest request) { if (request.getHeader(&quot ...

  3. vmstat 命令详解 转载

    vmstat 命令详解   procs:r-->在运行队列中等待的进程数b-->在等待io的进程数w-->可以进入运行队列但被替换的进程 memoyswap-->现时可用的交换 ...

  4. Android init进程概述

    init进程,其程序位于根文件系统中,在kernle自行启动后,其中的 start_kernel 函数把根文件系统挂载到/目录后,在 rest_init 函数中通过 kernel_thread(ker ...

  5. C&plus;&plus;里消除Wunused

    编译程序时,有一大堆警告总是不爽的.别人的代码也就忍了,不好去改.自己的可没法忍.看看C++里怎么消除Wunused警告. 先来看下面的程序: #include <iostream> in ...

  6. 【安德鲁斯】于java代码集drawableLeft给予适当的大小如何,当&quest;

    textView.setCompoundDrawables(drawable, null, null, null);如果看不到图片,这是由于需要手动定drawable适当的大小,使用drawable. ...

  7. 策略模式(stragegy)

    策略模式(stragegy) 定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法独立于使用算法的客户(Head First 设计模式).    策略模式,针对接口编程,而不依赖于具体的实 ...

  8. Android必知必会-获取视频文件的截图、缩略图

    背景 公司最近要求给我负责的APP加上视频录制和发布的功能,我简单的完成了基本的录制和视频压缩功能,后来发现发布接口需要上传视频的截图,网上搜索了一下资料,在这里整理一下. 代码实现 /** * 获取 ...

  9. ThinkPad T460进不去系统的解决方法

    系统卡在系统lenovo界面的尝试解决方案:开机点击F1进入到bios界面进入Security-Secure Boot选Disabled进入Startup-UEFI选BOTH 然后点击F10 选yes ...

  10. 【记】研究Sharding-JDBC遇到的一个异常&lpar;Caused by&colon; io&period;shardingsphere&period;core&period;exception&period;ShardingException&colon; Cannot get uniformed table structure for &grave;t&grave;&period; The different meta data of actual tables are as follows&rpar;

    一.异常信息 Caused by: io.shardingsphere.core.exception.ShardingException: Cannot get uniformed table str ...