kruscal重构树略解
我们先看一道题:Luogu P4197 Peaks
这道题珂以用启发式合并+主席树来做
那么强制在线呢?(bzoj 3551 [ONTAK2010]Peaks加强版)
离线做法就不行了
我们就要用一个叫做kruscal重构树的东西来解决这个问题
克鲁斯卡尔重构树可以用来解决一类诸如“查询从某个点出发经过边权不超过val的边所能到达的节点”的问题
首先不难发现,上面这个问题肯定是在最小生成树上走最优,其他边都可以不用去管
kruscal构树的思想就是在建最小生成树的时候不是直接连边,而是新建一个节点,并把这个节点的值设为边权,然后令两个连通块的代表点分别作为它的左右儿子。然后令这个新节点成为整个连通块的代表点
那么这样做有什么用呢?
kruscal重构树有这样的性质:一个点的所有子树节点的权值都小于等于它的权值,并且从它开始逐渐向子节点移动,权值是单调不上升的。这个性质是显然的,因为我们在构造树的时候是从小到大插入的边,因此父亲节点的权值一定大于等于子节点的值
查询时,首先可以在树上倍增得到当前查询点所能够到达的最远的祖先点,那么从这个点能够到达的符合边权限制条件的连通块中的节点,就是祖先点的子树中所有的叶节点
然后我们按dfs序维护一个主席树上树就可以解决了
完整代码(离线)
#include <bits/stdc++.h>
#define getchar nc
#define N 200005
#define M N<<4
#define K 500005
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
struct node{
int u,v,c;
node(){}
node(int u,int v,int c):u(u),v(v),c(c){}
inline bool operator <(const node &b)const
{
return c<b.c;
}
}E[K];
struct edge{
int to,next;
}e[N];
int head[N],tot;
inline void add(register int u,register int v)
{
e[++tot]=(edge){v,head[u]};
head[u]=tot;
}
int n,m,q,limit,dfn;
int bin[25];
int fa[N],val[N],f[N][20];
int b[N>>1],h[N>>1];
int ls[N],rs[N],rt[N],num;
int sum[M],L[M],R[M],cnt;
inline void mission(register int x)
{
for(register int i=1;bin[i]<=n;++i)
f[x][i]=f[f[x][i-1]][i-1];
}
inline void update(register int last,register int &now,register int l,register int r,register int x)
{
sum[now=++cnt]=sum[last]+1;
if(l==r)
return;
int mid=l+r>>1;
if(x<=mid)
R[now]=R[last],update(L[last],L[now],l,mid,x);
else
L[now]=L[last],update(R[last],R[now],mid+1,r,x);
}
inline int query(register int a,register int x,register int k)
{
int l=1,r=limit;
for(register int j=18;~j;--j)
if(f[a][j]&&val[f[a][j]]<=x)
a=f[a][j];
int v=rt[rs[a]],u=rt[ls[a]-1];
if(sum[v]-sum[u]<k)
return -1;
while(l<r)
{
int tmp=sum[R[v]]-sum[R[u]],mid=l+r>>1;
if(tmp>=k)
v=R[v],u=R[u],l=mid+1;
else
v=L[v],u=L[u],r=mid,k-=tmp;
}
return b[r];
}
inline void dfs(register int u)
{
mission(u);
ls[u]=++num;
if(u<=n)
update(rt[num-1],rt[num],1,limit,h[u]);
else
rt[num]=rt[num-1];
for(register int i=head[u];i;i=e[i].next)
dfs(e[i].to);
rs[u]=num;
}
inline int find(register int x)
{
return x==fa[x]?x:fa[x]=find(fa[x]);
}
int main()
{
n=read(),m=read(),q=read();
bin[1]=1;
for(register int i=2;i<=22;++i)
bin[i]=bin[i-1]<<1;
for(register int i=1;i<=n<<1;++i)
fa[i]=i;
for(register int i=1;i<=n;++i)
b[i]=h[i]=read();
sort(b+1,b+n+1);
limit=unique(b+1,b+n+1)-b-1;
for(register int i=1;i<=n;++i)
h[i]=lower_bound(b+1,b+limit+1,h[i])-b;
for(register int i=1;i<=m;++i)
{
int u=read(),v=read(),c=read();
E[i]=node(u,v,c);
}
sort(E+1,E+m+1);
dfn=n;
for(register int i=1;i<=m;++i)
{
int u=find(E[i].u),v=find(E[i].v);
if(u!=v)
{
val[++dfn]=E[i].c;
fa[u]=fa[v]=dfn;
add(dfn,u),add(dfn,v);
f[u][0]=f[v][0]=dfn;
if(dfn-n==n-1)
break;
}
}
for(register int i=1;i<=dfn;++i)
if(!ls[i])
dfs(find(i));
while(q--)
{
int v=read(),x=read(),k=read();
write(query(v,x,k)),puts("");
}
return 0;
}
完整代码(在线)
#include <bits/stdc++.h>
#define getchar nc
#define N 200005
#define M N<<4
#define K 500005
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
struct node{
int u,v,c;
node(){}
node(int u,int v,int c):u(u),v(v),c(c){}
inline bool operator <(const node &b)const
{
return c<b.c;
}
}E[K];
struct edge{
int to,next;
}e[N];
int head[N],tot;
inline void add(register int u,register int v)
{
e[++tot]=(edge){v,head[u]};
head[u]=tot;
}
int n,m,q,limit,dfn;
int bin[25];
int fa[N],val[N],f[N][20];
int b[N>>1],h[N>>1];
int ls[N],rs[N],rt[N],num;
int sum[M],L[M],R[M],cnt;
inline void mission(register int x)
{
for(register int i=1;bin[i]<=n;++i)
f[x][i]=f[f[x][i-1]][i-1];
}
inline void update(register int last,register int &now,register int l,register int r,register int x)
{
sum[now=++cnt]=sum[last]+1;
if(l==r)
return;
int mid=l+r>>1;
if(x<=mid)
R[now]=R[last],update(L[last],L[now],l,mid,x);
else
L[now]=L[last],update(R[last],R[now],mid+1,r,x);
}
inline int query(register int a,register int x,register int k)
{
int l=1,r=limit;
for(register int j=18;~j;--j)
if(f[a][j]&&val[f[a][j]]<=x)
a=f[a][j];
int v=rt[rs[a]],u=rt[ls[a]-1];
if(sum[v]-sum[u]<k)
return -1;
while(l<r)
{
int tmp=sum[R[v]]-sum[R[u]],mid=l+r>>1;
if(tmp>=k)
v=R[v],u=R[u],l=mid+1;
else
v=L[v],u=L[u],r=mid,k-=tmp;
}
return b[r];
}
inline void dfs(register int u)
{
mission(u);
ls[u]=++num;
if(u<=n)
update(rt[num-1],rt[num],1,limit,h[u]);
else
rt[num]=rt[num-1];
for(register int i=head[u];i;i=e[i].next)
dfs(e[i].to);
rs[u]=num;
}
inline int find(register int x)
{
return x==fa[x]?x:fa[x]=find(fa[x]);
}
int main()
{
n=read(),m=read(),q=read();
bin[1]=1;
for(register int i=2;i<=22;++i)
bin[i]=bin[i-1]<<1;
for(register int i=1;i<=n<<1;++i)
fa[i]=i;
for(register int i=1;i<=n;++i)
b[i]=h[i]=read();
sort(b+1,b+n+1);
limit=unique(b+1,b+n+1)-b-1;
for(register int i=1;i<=n;++i)
h[i]=lower_bound(b+1,b+limit+1,h[i])-b;
for(register int i=1;i<=m;++i)
{
int u=read(),v=read(),c=read();
E[i]=node(u,v,c);
}
sort(E+1,E+m+1);
dfn=n;
for(register int i=1;i<=m;++i)
{
int u=find(E[i].u),v=find(E[i].v);
if(u!=v)
{
val[++dfn]=E[i].c;
fa[u]=fa[v]=dfn;
add(dfn,u),add(dfn,v);
f[u][0]=f[v][0]=dfn;
if(dfn-n==n-1)
break;
}
}
for(register int i=1;i<=dfn;++i)
if(!ls[i])
dfs(find(i));
int lastans=0,v,x,k;
while(q--)
{
if(~lastans)
v=read()^lastans,x=read()^lastans,k=read()^lastans;
else
v=read(),x=read(),k=read();
write(lastans=query(v,x,k)),puts("");
}
return 0;
}
kruscal重构树略解的更多相关文章
- loj2876 水壶 [JOISC 2014 Day2] kruscal重构树
正解:kruscal重构树+bfs 解题报告: 我永远喜欢loj! 感觉这题和这题挺像的,,,预处理和解题方法都是,,,所以大概整体二分能过去? 但因为做这题主要是入门一下kruscal重构树,,,所 ...
- $ CometOJ-Contest\#11\ D$ $Kruscal$重构树
正解:$Kruscal$重构树 解题报告: 传送门$QwQ$ 发现一个图上搞就很麻烦,考虑变为生成树达到原有效果. 因为在询问的时候是要求走到的点编号尽量小,发现这个时候点的编号就成为限制了,于是不难 ...
- 洛谷$P4768\ [NOI2018]$归程 $kruscal$重构树
正解:$kruscal$重构树 解题报告: 传送门$QwQ$ 语文不好选手没有人权$TT$连题目都看不懂真的要哭了$kk$ 所以先放个题目大意?就说给定一个$n$个点,$m$条边的图,每条边有长度和海 ...
- 『Kruscal重构树 Exkruscal』
新增一道例题及讲解 Exkruscal \(Exkruscal\)又称\(Kruscal\)重构树,是一种利用经典算法\(Kruscal\)来实现的构造算法,可以将一张无向图重构为一棵具有\(2n-1 ...
- BZOJ_3545_[ONTAK2010]Peaks_主席树+倍增+kruscal重构树+dfs序
BZOJ_3545_[ONTAK2010]Peaks_主席树+倍增+kruscal重构树 Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道 ...
- [NOI2018]归程(kruscal重构树)
[NOI2018]归程 题面太长辣,戳这里 模拟赛上写了一个spfa (关于spfa,它已经死了),然后一个st表水完暴力跑路.考后说是Kruscal重构树或者可持久化并查集???这都是些什么东西.不 ...
- 学习笔记:Kruscal 重构树
网上感觉没有什么很详细 + 证明的讲解啊) 前置:Kruskal 求最小生成树. 这个算法可以将一棵树 / 无向连通图重构成一颗有性质的新树. 算法可以解决一些树上瓶颈边权之类的问题,可以把需要持久化 ...
- 【题解】洛谷P1967 [NOIP2013TG] 货车运输(LCA+kruscal重构树)
洛谷P1967:https://www.luogu.org/problemnew/show/P1967 思路 感觉2013年D1T3并不是非常难 但是蒟蒻还是WA了一次 从题目描述中看出每个点之间有许 ...
- BZOJ_5415_[Noi2018]归程_kruscal重构树+倍增+最短路
BZOJ_5415_[Noi2018]归程_kruscal重构树+倍增 Description www.lydsy.com/JudgeOnline/upload/noi2018day1.pdf 好久不 ...
随机推荐
- h5 ios手机 隐藏input输入光标
前面在做一个H5中用到的6位数字密码弹框(类似支付.微信那种)时,遇到一个可怕问题,那就是在浏览器和安卓中是不显示输入光标的,但是在ios手机上光标总是能看见,像穿透一样地显示最外层. 先说下实现密码 ...
- 帝国CMS 您来自的链接不存在
网上的解决方法如下. 我是在通过接口,发布新闻,然后点击修改的时候,提示这个. 网上的方法,是让检查这个栏目下,有没有设置默认模板,包括:列表模板和内容模板,如果没有,就设定一下,再“更新数据库缓 ...
- 线程的条件Condiition
条件Condition相当于给锁造钥匙,但是这钥匙是一次性的.一个线程拿到钥匙进去,出来之后钥匙没有归还,而是没了. 如下代码: from threading import Thread, Condi ...
- C# word 图片大小
通过Office自带的类库word文档中插入图片,图片大小的单位为磅 而文档中,图片的大小已经固定,为CM. 实际工作中,首先将图片插入到word中,根据目前的大小,计算转换为目标大小的比率,将长宽按 ...
- word-break和word-wrap的使用和区别
问题起源: 中文是一个字就是一个单词,而英文字母要有一个空格才将他们分割为一个单词:文字换行没事,主要是英文 <!DOCTYPE html> <html> <head&g ...
- 怎么将APE转MP3,APE转MP3的方法
怎样实现APE转MP3的问题呢?很多时候我们从网上所下载的音乐格式,可能并不是我们所需要的音乐格式.如APE音乐格式,那么当我们下载了自己并不需要的APE音乐格式我们应该如何将其转换为自己需要的MP3 ...
- day20:序列化模块,模块的导入
1,什么是序列化--将原本的字典,列表等内容转换成一个字符串的过程就叫做序列化,字符串是有顺序的,序列化转向一个字符串的过程,我们平时说的序列,指的就是字符串. 2,为何要序列化?本来字符串是可以强转 ...
- 【WordCount】实现(重做)
Gitee项目地址: https://gitee.com/LIUJIA6/wordcount_implementation 需求说明: WordCount的需求可以概括为:对程序设计语言源文件统计字符 ...
- Linux学习8-CentOS部署自己本地的django项目
前言 自己本地写好的django项目,如何部署到linux服务器上,让其他的小伙伴也能访问呢?本篇以centos系统为例,把本地写好的django项目部署到linux服务器上 环境准备: 环境准备: ...
- ES6 Reflect 与 Proxy
概述 Proxy 与 Reflect 是 ES6 为了操作对象引入的 API . Proxy 可以对目标对象的读取.函数调用等操作进行拦截,然后进行操作处理.它不直接操作对象,而是像代理模式,通过对象 ...