3545: [ONTAK2010]Peaks

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1202  Solved: 321
[Submit][Status][Discuss]

Description

在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。

Input

第一行三个数N,M,Q。
第二行N个数,第i个数为h_i
接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径。
接下来Q行,每行三个数v x k,表示一组询问。

Output

对于每组询问,输出一个整数表示答案。

Sample Input

10 11 4
1 2 3 4 5 6 7 8 9 10
1 4 4
2 5 3
9 8 2
7 8 10
7 1 4
6 7 1
6 4 8
2 1 5
10 8 10
3 4 7
3 4 6
1 5 2
1 5 6
1 5 8
8 9 2

Sample Output

6
1
-1
8

HINT

【数据范围】

N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。

Source

By Sbullet

3551: [ONTAK2010]Peaks加强版

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 810  Solved: 275
[Submit][Status][Discuss]

第一行三个数N,M,Q。
第二行N个数,第i个数为h_i
接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径。
接下来Q行,每行三个数v x k,表示一组询问。v=v xor lastans,x=x xor lastans,k=k xor lastans。如果lastans=-1则不变。

Solution

先是非加强版,不强制在线,可以考虑离线,进行排序然后平衡树启发式合并搞搞就可以。

加强版要异或lastans,很显然不能上述做法,按照出题人的做法去搞:

首先我们发现,对结果有贡献的边,即最小生成树上的边,其余的边都是无用的,所以不妨先Kruskal建出最小生成树

但是这里的Kruskal与以往有不同,以往是直接连边,而这里需要 用到另一种方式 即 Kruskal重构树

具体方法很简单,以前是按边排序,用并查集维护联通性,每次连最小的边,这里思路类似,但是不是直接连边,而是构造一个新的节点,向这个边的两个端点连边,点权为这条边的边权(注意这里是单向边)

这里的Kruskal重构树有一些有用的性质:

1.二叉树(好吧这题意义不大)

2.原树与新树两点间路径上边权(点权)的最大值相等

3.子节点的边权小于等于父亲节点(大根堆)

4.原树中两点之间路径上边权的最大值等于新树上两点的LCA的点权

对于维护路径上的最值,就可以考虑倍增,倍增出来之后,建棵主席树,每次询问区间第K即可

PS.Claris好像有种方法,利用线段树合并来做,具体的并不会 ,但大体上会个板子

int merge(int x,int y,int a,int b)
{
if (!x) return y;
if (!y) return x;
int z=++tot;
if (a==b)
v[z]=v[x]+v[y],return z;
int mid=(a+b)>>;
l[z]=merge(l[x],l[y],a,mid);
r[z]=merge(r[x],r[y],mid+,b);
v[z]=v[l[z]]+v[r[z]];
return z;
}

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-')f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define maxn 100100
#define maxm 500100
int n,m,q; int hh[maxn],ls[maxn]; int steck[maxn<<],top;
struct data{
int from,to,hard;
bool operator < (const data& A) const
{return hard<A.hard;}
}road[maxm];
struct dat{int next,to;}edge[maxn<<];int head[maxn<<],cnt;
void add(int u,int v){cnt++;edge[cnt].next=head[u];head[u]=cnt;edge[cnt].to=v;}
int fa[maxn<<],va[maxn<<];
void init(){for (int i=; i<=n*; i++) fa[i]=i;}
int find(int x) {if (x==fa[x]) return x; return fa[x]=find(fa[x]);}
void Kruskal()
{
init(); int zz=n;
sort(road+,road+m+);
for (int i=; i<=m; i++)
{ int u=road[i].from,v=road[i].to,w=road[i].hard;
int fa1=find(u),fa2=find(v);
if (fa1!=fa2)
{
zz++; fa[fa1]=fa[fa2]=zz; va[zz]=w;
add(zz,fa2);add(zz,fa1);
if (zz==*n-) break;
}
}
}
bool visit[maxn<<];int father[maxn<<][],maxx[maxn<<][],deep[maxn<<];
void dfs(int x)
{
visit[x]=; steck[++top]=x;
for (int i=; i<; i++)
if (deep[x]>=(<<i))
father[x][i]=father[father[x][i-]][i-],
maxx[x][i]=max(maxx[x][i-],maxx[father[x][i-]][i-]);
else break;
for (int i=head[x]; i; i=edge[i].next)
{
deep[edge[i].to]=deep[x]+;
maxx[edge[i].to][]=va[x];
father[edge[i].to][]=x;
dfs(edge[i].to);
}
if (x>n) steck[++top]=x;
}
int sum[maxn*],ll[maxn*],rr[maxn*],root[maxn<<],sz;
void insert(int l,int r,int &now,int fat,int val)
{
now=++sz; sum[now]=sum[fat]+;
if (l==r) return;
ll[now]=ll[fat],rr[now]=rr[fat];
int mid=(l+r)>>;
if (val<=mid) insert(l,mid,ll[now],ll[fat],val);
else insert(mid+,r,rr[now],rr[fat],val);
}
int query(int l,int r,int L,int R,int kth)
{
if (l==r) return l;
int mid=(l+r)>>;
if (sum[ll[R]]-sum[ll[L]]>=kth) return query(l,mid,ll[L],ll[R],kth);
else return query(mid+,r,rr[L],rr[R],kth-sum[ll[R]]+sum[ll[L]]);
}
int st[maxn<<],ed[maxn<<];
void prework()
{
for (int i=; i<=n; i++)
if (!visit[i]) dfs(find(i));
for (int i=; i<=top; i++)
{
int tmp=steck[i];
if (tmp<=n) insert(,n,root[i],root[i-],hh[tmp]);
else
{
root[i]=root[i-];
if (!st[tmp]) st[tmp]=i; else ed[tmp]=i;
}
}
}
int search(int x,int val)
{
for(int i=;i>=;i--)
if(deep[x]>=(<<i) && maxx[x][i]<=val) x=father[x][i];
return x;
}
int main()
{
n=read(),m=read(),q=read();
for (int i=; i<=n; i++) hh[i]=read(),ls[i]=hh[i];
sort(ls+,ls+n+);
for (int i=; i<=n; i++)
hh[i]=lower_bound(ls+,ls+n+,hh[i])-ls;
for (int i=; i<=m; i++)
road[i].from=read(),road[i].to=read(),road[i].hard=read();
Kruskal();
prework();
int lastans=-,ans;
for (int i=; i<=q; i++)
{
int v=read(),x=read(),k=read();
if (lastans!=-) v^=lastans,x^=lastans,k^=lastans;
int tmp=search(v,x);
int a=root[st[tmp]],b=root[ed[tmp]];
if (sum[b]-sum[a]<k) ans=-;
else ans=ls[query(,n,a,b,sum[b]-sum[a]-k+)];
printf("%d\n",ans); lastans=ans;
}
return ;
}

开始RE,后来MLE,后来WA,如此这般...简直不要太坑...外加本机Gena测全WA,提交AC....背水淹没

【BZOJ-3545&3551】Peaks&加强版 Kruskal重构树 + 主席树 + DFS序 + 倍增的更多相关文章

  1. [BZOJ3551][ONTAK2010]Peaks(加强版)(Kruskal重构树,主席树)

    3551: [ONTAK2010]Peaks加强版 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2438  Solved: 763[Submit][ ...

  2. BZOJ3545&3551[ONTAK2010]Peaks——kruskal重构树+主席树+dfs序+树上倍增

    题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只 ...

  3. BZOJ.3551.[ONTAK2010]Peaks加强版(Kruskal重构树 主席树)

    题目链接 \(Description\) 有n个座山,其高度为hi.有m条带权双向边连接某些山.多次询问,每次询问从v出发 只经过边权<=x的边 所能到达的山中,第K高的是多少. 强制在线. \ ...

  4. luoguP4197:Peaks(Kruskal重构树+主席树)或者(点分树+离线)

    题意:有N座山,M条道路.山有山高,路有困难值(即点权和边权).现在Q次询问,每次给出(v,p),让求从v出发,只能结果边权<=p的边,问能够到达的山中,第K高的高度(从大到小排序). 思路:显 ...

  5. BZOJ 3551: [ONTAK2010]Peaks加强版 [Kruskal重构树 dfs序 主席树]

    3551: [ONTAK2010]Peaks加强版 题意:带权图,多组询问与一个点通过边权\(\le lim\)的边连通的点中点权k大值,强制在线 PoPoQQQ大爷题解传送门 说一下感受: 容易发现 ...

  6. 【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

    这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,L ...

  7. BZOJ 3551: [ONTAK2010]Peaks加强版 Kruskal重构树+dfs序+主席树+倍增

    建出来 $Kruskal$ 重构树. 将询问点向上跳到深度最小,且合法的节点上. 那么,得益于重构树优美的性质,这个最终跳到的点为根的所有子节点都可以与询问点互达. 对于子树中求点权第 $k$ 大的问 ...

  8. BZOJ3551 Peaks加强版 [Kruskal重构树,主席树]

    BZOJ 思路 我觉得这题可持久化线段树合并也可以做 我觉得这题建出最小生成树之后动态点分治+线段树也可以做 还是学习一下Kruskal重构树吧-- Kruskal重构树,就是在做最小生成树的时候,如 ...

  9. luogu4197 Peaks (kruskal重构树+主席树)

    按照边权排序建出kruskal重构树,每次就变成了先找一个权值<=x的最远的祖先,然后看这个子树的第k小.离散化一下,在dfs序上做主席树即可 而且只需要建叶节点的主席树 注意输出的是第k小点的 ...

随机推荐

  1. 字典树(Tire)模板

    #include<stdio.h> #include<string.h> #include<stdlib.h> struct node { node *ne[]; ...

  2. AC日记——机器翻译 洛谷 P1540

    题目背景 小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章. 题目描述 这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换.对于每个英文单词,软件会先 ...

  3. jira与readmine区别

    JIRA适合多人的团队(100+),而Readmine适合中小型团队. Redmine是用ruby开发的基于web的项目管理软件,免费.JIRA收费Redmine可以创建子任务,而jira不易创建子任 ...

  4. SqlServer 注入技巧

    一.SA权限执行命令,如何更快捷的获取结果? 有显示位 显示位 其实这里的关键并不是有无显示位.exec master..xp_cmdshell 'systeminfo'生成的数据写进一张表的时候,会 ...

  5. Idea maven tomcat 配置热更新 以及 maven jar依赖

    看了视频 实在忍不住上了idea的贼船 不过这玩意确实有点坑爹,因为用的人少,所以很多配置是有问题的 例如maven配置tomcat热更新 以及tomcat的maven配置 我这里放几张图作为备用 配 ...

  6. 用mel编写自定义节点的属性编辑器界面

    用mel编写自定义节点的属性编辑器界面比较麻烦,而且网上例子又少,下面给出一个范例,说明基本的格式 // 初始化节点时调用 global proc initControl(string $attrNa ...

  7. Javascript中call和apply的区别与详解

    在js中call和apply它们的作用都是将函数绑定到另外一个对象上去运行,两者仅在定义参数方式有所区别,下面我来给大家介绍一下call和apply用法: 在web前端开发过程中,我们经常需要改变th ...

  8. 05JavaIO详解_仿照IO源码自己去实现一个IO流(为了加深印象,本身没有价值)

    版本会越来越难: 版本1:只写一个read方法 package com.guigu.shen.InputStream; import java.io.IOException; import java. ...

  9. usb驱动开发5之总线设备与接口

    Linux设备模型中的总线落实在USB子系统里就是usb_bus_type,它在usb_init的函数bus_register(&usb_bus_type)里注册.usb_bus_type定义 ...

  10. 客户端缓存(Client Cache)

    通常在服务器端大家都已经做了很多缓存的工作,ASP.NET CACHE也好MemeryCache也好却总是忽略了客户端缓存. 因为大家都知道不管哪个client都会缓存已经访问过的站点,但是浏览器缓存 ...