您的位置:首页 > 其它

[bzoj3545+3551][ONTAK2010]Peaks&&加强版(离线+线段树合并)||(kruskal重构树&&dfs序+主席树)

2017-10-27 18:10 543 查看
传送门

没权限号可以来这里交,老规矩,不准说。

题面

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。

题解

首先,这个题有一个比较明显的做法,就是离线处理。

我们把边按权值排序,然后不断加入边,处理询问,加边的时候可以启发式合并。

然后时间复杂度就是O(nlog2n)了。

然后就有了另一个题:bzoj3551 peaks加强版(强制在线)

这个我也是才学,不会讲,还是放po姐的博客吧:

http://blog.csdn.net/PoPoQQQ/article/details/41348785

那个图就是样例输入的重构树,大家可以自己模拟一下它是如何建出来的。

还有,那几个性质好好想一想。

然后应该就懂了,po姐还是讲得很好的。

过程:

1.读入

2.离散化

3.做kruskal,同时构造出重构树

4.在kruskal重构树上dfs一遍,然后找出dfs序(只有叶子)和每个节点的子树中的叶子数量,以及每个点的子树在dfs序上的起始位置

5.在dfs序上建主席树

6.利用kruskal重构树的性质,我们只需要在dfs时处理出来每个点向上跳2^j步的位置,然后倍增地去跳到权值<=限制权值的深度最小的点,它的子树就是限制下可以到达的所有节点。

7.对于查询,我们在主席树上利用之前的信息直接查询即可。

跑得好慢

分别是9632ms(3545),17124ms(3551)

都是卡线呀(滑稽)

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<vector>
#include<queue>
#define ll long long
using namespace std;
inline int read(){
int x=0,f=1;char ch=' ';
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-48,ch=getchar();
return x*f;
}
const int N=1e5+500;
const int M=5e5+500;
struct kedge{
int x,y,l;
inline bool operator < (const kedge& b) const {return l<b.l;}
}e[M];
struct edge{
int to,next;
}e1[M<<1],e2[M+N];
int n,m,q,tot1,tot2,tot,hash_cnt;
int h
,fa[N+M],head1
,head2[N+M],w[N+M],dep[N+M],b
;
inline void addedge1(int x,int y){e1[++tot1].to=y;e1[tot1].next=head1[x];head1[x]=tot1;}
inline void addedge2(int x,int y){e2[++tot2].to=y;e2[tot2].next=head2[x];head2[x]=tot2;}
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void kruskal(){
for(int i=1;i<=n;i++)fa[i]=i,w[i]=h[i];
sort(e+1,e+m+1);tot=n;int j=n;
for(int i=1;i<=m;i++){
int x=e[i].x;int y=e[i].y;int l=e[i].l;
int u=find(x);int v=find(y);
if(u==v)continue;
w[++tot]=l;
addedge2(tot,u);addedge2(tot,v);
fa[u]=fa[v]=fa[tot]=tot;
j--;if(j==1)break;
}
}
struct node{
int ls,rs,size;
}t[N*25];
int st[20][N+M],size[N+M],dfn[N+M],dfn_clock,cnt,root[N+M],mp[N+M],start[N+M];
inline void dfs(int x){
for(int k=1;k<=19&&(1<<k)<=dep[x];k++){
st[k][x]=st[k-1][st[k-1][x]];
}
size[x]=0;start[x]=dfn_clock+1;
if(x<=n)dfn[++dfn_clock]=x,size[x]++,mp[x]=dfn_clock;
for(int i=head2[x];i;i=e2[i].next){
int u=e2[i].to;
st[0][u]=x;dep[u]=dep[x]+1;
dfs(u);
size[x]+=size[u];
}
}
inline void build(int &now,int l,int r){
now=++cnt;
if(l==r)return;
int mid=(l+r)>>1;
build(t[now].ls,l,mid);
build(t[now].rs,mid+1,r);
}
inline void insert(int &now,int pre,int l,int r,int x){
now=++cnt;
t[now]=t[pre];
t[now].size++;
if(l==r)return;
int mid=(l+r)>>1;
if(x<=mid)insert(t[now].ls,t[pre].ls,l,mid,x);
else insert(t[now].rs,t[pre].rs,mid+1,r,x);
}
inline int kth(int now,int pre,int l,int r,int k){
if(l==r){
if(k>t[now].size-t[pre].size)return -1;
else return b[l];
}
int rsize=t[t[now].rs].size-t[t[pre].rs].size;
int mid=(l+r)>>1;
if(k<=rsize)return kth(t[now].rs,t[pre].rs,mid+1,r,k);
else return kth(t[now].ls,t[pre].ls,l,mid,k-rsize);
}
inline void make(){
build(root[0],1,hash_cnt);
for(int i=1;i<=dfn_clock;i++){
h[dfn[i]]=lower_bound(b+1,b+hash_cnt+1,h[dfn[i]])-b;
insert(root[i],root[i-1],1,hash_cnt,h[dfn[i]]);
}
}
inline int jump(int x,int V){
for(int k=19;k>=0;k--){
if(st[k][x]&&w[st[k][x]]<=V){
x=st[k][x];
}
}
return x;
}
int main(){
n=read();m=read();q=read();
for(int i=1;i<=n;i++)h[i]=read(),b[i]=h[i];
sort(b+1,b+n+1);
hash_cnt=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=m;i++){
int x=read(),y=read(),l=read();
addedge1(x,y);addedge1(y,x);
e[i].x=x;e[i].y=y;e[i].l=l;
}
kruskal();
dep[tot]=1;
dfs(tot);
make();
int lastans=0;
while(q--){
int x=read()^lastans,V=read()^lastans,k=read()^lastans;
int top=jump(x,V);
lastans=kth(root[start[top]+size[top]-1],root[start[top]-1],1,hash_cnt,k);
printf("%d\n",lastans);
if(lastans==-1)lastans=0;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐