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,表示一组询问。v=v xor lastans,x=x xor lastans,k=k xor lastans。如果lastans=-1则不变。
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
10
9
-1
HINT
【数据范围】
N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。
分析:
Kruskal树+主席树
一开始我以为要把所有的边都建到kruskal树上
但是边好多,而且好像办不到啊
后来仔细一想
题目要求是在<=x的边上移动
只要找到最小生成树就可以了
也许会有这样的疑问
一条边<=x
但是ta连接的两个点一定在一个联通快内了,那么x就连不上了,这怎么办呢
没有做到在所有<=x的边上移动啊
但是仔细考虑一下我们的命题
x连接的两个点已经联通了,那加不加x这条边都没有影响啊
整理一下代码思路吧:
一.如果要用数组存储主席树的话
一上来就要对高度进行离散(神烦)
二.一个很普通的kruskal构建,我这里用的是自己yy的做法
三.倍增维护爸爸和权值
**四.**dfs 这个dfs很鬼,只有是叶子结点的才能算入dfs序
五.构建主席树
因为我几乎不会主席树,所以找的网上dalao的代码(纯结构体,我喜欢)
其实就是把每个高度扔进树里,每扔一个数root+1表示时间的推移
因为我们是按照dfs序来进行的构建,所以一棵子树的root一定是一个区间
主席树节点中要记录左儿子,右儿子和树中的元素数目
六.处理询问
注意,初始ans=1
询问的处理就像线段树一样,
因为提问的是第k高,所以就是从后往前数的第k个
如果区间右儿子的值相减大于x,那我们直接进入x
否则进入左儿子,但是x的值要相应的处理
-tree[tree[y].r].sz+tree[tree[x].r].sz
tip
数组一定要开够了
主席树的空间nlogn,200000*20
这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=200005;
struct node{
int x,y,v;
};
node e[500010];
struct nd{
int x,y,nxt;
};
nd way[N];
int mx[N][20],lg,f[N][20];
int n,m,h[N],Q,fa[N],tot=0,st[N],in[N],out[N],cnt=0,tt,H,hh[N],root[N];
int a[N],total=0,ans=0;
struct nod{
int l,r,sz;
};
nod tree[4000000];
struct point{
int x,bh;
};
point po[N];
void add(int u,int w)
{
tot++;
way[tot].x=u;way[tot].y=w;way[tot].nxt=st[u];st[u]=tot;
}
int cmp2(const point &a,const point &b){return a.x<b.x;}
int cmp(const node &a,const node &b){return a.v<b.v;}
int find(int a)
{
if (fa[a]!=a) fa[a]=find(fa[a]);
return fa[a];
}
void kruskal()
{
int i,j,o=0;
tt=n;
sort(e+1,e+1+m,cmp);
for (int i=1;i<=n+n;i++) fa[i]=i;
for (i=1;i<=m;i++)
{
int f1=find(e[i].x);
int f2=find(e[i].y);
if (f1!=f2)
{
fa[f1]=fa[f2]=++tt; //并查集
f[f1][0]=f[f2][0]=tt; //papa
mx[f1][0]=mx[f2][0]=e[i].v; //最大值
add(tt,f1);add(tt,f2);
o++;
}
if (o==n-1) break;
}
}
void dfs(int x)
{
in[x]=a[0];
if (st[x]==0) a[++a[0]]=x; //dfs
for (int i=st[x];i;i=way[i].nxt)
dfs(way[i].y);
out[x]=a[0];
}
void insert(int x,int &y,int l,int r,int z)
{
y=++total; //total节点计数
if (l==r)
{
tree[y].sz=tree[x].sz+1;
return;
}
int mid=(l+r)>>1;
if (z<=mid) tree[y].r=tree[x].r,insert(tree[x].l,tree[y].l,l,mid,z);
else tree[y].l=tree[x].l,insert(tree[x].r,tree[y].r,mid+1,r,z);
tree[y].sz=tree[tree[y].l].sz+tree[tree[y].r].sz;
}
void ask(int x,int y,int l,int r,int k)
{
if (l==r)
{
ans=hh[l]; //山峰高度
return;
}
int mid=(l+r)>>1;
if (tree[tree[y].r].sz-tree[tree[x].r].sz>=k) return ask(tree[x].r,tree[y].r,mid+1,r,k);
else return ask(tree[x].l,tree[y].l,l,mid,k-tree[tree[y].r].sz+tree[tree[x].r].sz);
//因为提问的是第k高,所以就是从后往前数的第k个
}
int main()
{
scanf("%d%d%d",&n,&m,&Q);
for (int i=1;i<=n;i++) scanf("%d",&po[i].x),po[i].bh=i;
sort(po+1,po+1+n,cmp2);
H=0;
hh[H]=-1;
for (int i=1;i<=n;i++){
if (hh[H]<po[i].x) hh[++H]=po[i].x; //hh[H] H对应的数字
h[po[i].bh]=H; //离散后的答案
}
for (int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v);
kruskal();
lg=log(tt)/log(2);
for (int i=1;i<=lg;i++) //倍增
for (int j=1;j<=tt;j++)
f[j][i]=f[f[j][i-1]][i-1],
mx[j][i]=max(mx[j][i-1],mx[f[j][i-1]][i-1]);
dfs(tt);
for (int i=1;i<=n;i++) insert(root[i-1],root[i],1,H,h[a[i]]); //按照dfs序添加
for (int i=1;i<=Q;i++)
{
int u,w,z;
scanf("%d%d%d",&u,&w,&z);
u^=ans;w^=ans;z^=ans;
int temp=u;
for (int j=lg;j>=0;j--) //找到符合条件的lca
if (f[temp][j]&&mx[temp][j]<=w) //lca<=x
temp=f[temp][j]; //temp=lca-1
if (out[temp]-in[temp]<z)
{
puts("-1");
ans=0;
continue;
}
ask(root[in[temp]],root[out[temp]],1,H,z);
//一开始还在奇怪为什么不是in[temp]-1,仔细想了一下在计算lca的时候我们已经少算了一个1了
printf("%d
",ans);
}
return 0;
}