題目
Description
在Bytemountains有座山峯,每座山峯有他的高度。有些山峯之間有雙向道路相連,共條路徑,每條路徑有一個困難值,這個值越大表示越難走,現在有組詢問,每組詢問詢問從點開始只經過困難值小於等於的路徑所能到達的山峯中第高的山峯,如果無解輸出-1
。
Input
第一行三個數,,。
第二行個數,第個數爲
接下來行,每行個數,表示從到有一條困難值爲的雙向路徑。
接下來行,每行三個數,表示一組詢問。,,。如果則不變。
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
Data Constraint
,,。
Source
By Sbullet
分析
建Kruskal重構樹,然後就可以用倍增的方法求得“從點開始只經過困難值小於等於的路徑所能到達的山峯”:
- 令是的,深度最小的,點權小於等於的,一個祖先;
- 那麼的子樹的所有葉結點就是“從點開始只經過困難值小於等於的路徑所能到達的山峯”。
然後查詢這些葉結點中的區間第大,主席樹即可。
(可持久化線段樹的坑以後再填吧,,,,,)
代碼
注意看一下注釋的地方。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0;bool f=0;char c=getchar();
while(c<'0'||c>'9') f|=c=='-',c=getchar();
while(c>='0'&&c<='9') x=x*10+(c^48),c=getchar();
return f?-x:x;
}
#define LOG 20
#define MAXN 100000
#define MAXM 500000
#define MAXP (2*MAXN)
int N,M,Q;
int H[MAXN+5];
struct Edge{
int u,v,w;
}E[MAXM+5];
bool cmp(Edge i,Edge j){
return i.w<j.w;
}
int fa[MAXP+5];
void Init(int n){
for(int i=1;i<=n;i++)
fa[i]=i;
}
int Find(int u){
return fa[u]==u?u:fa[u]=Find(fa[u]);
}
int Num[MAXN+5];
int Rev[MAXN+5];
map<int,int> ID;
struct SegmentTree{
#define lch (T[i].ch[0])
#define rch (T[i].ch[1])
struct Node{
int cnt;
int ch[2];
}T[MAXN*LOG*8+5];
int N,cnt,Root[MAXP+5];
void PushUp(int i){
T[i].cnt=T[lch].cnt+T[rch].cnt;
}
void Insert(int &i,int l,int r,int val,int Last){
//不能寫這種,要在進入之前判,否則會被卡常!!!!!
// if(val<l||val>r)
// return;
T[i=++cnt]=T[Last];
if(l==r){
T[i].cnt++;
return;
}
int mid=(l+r)>>1;
if(val<=mid)
Insert(lch,l,mid,val,T[Last].ch[0]);
else
Insert(rch,mid+1,r,val,T[Last].ch[1]);
PushUp(i);
}
int Query(int i,int l,int r,int kth,int Last){
if(l==r)
return l;
int mid=(l+r)>>1;
int lcnt=T[lch].cnt-T[T[Last].ch[0]].cnt;
if(lcnt>=kth)
return Query(lch,l,mid,kth,T[Last].ch[0]);
return Query(rch,mid+1,r,kth-lcnt,T[Last].ch[1]);
}
#undef lch
#undef rch
}T;
#define lch (K[i].ch[0])
#define rch (K[i].ch[1])
struct KruskalNode{
int ch[2];
int w,l,r,id;
}K[MAXP+5];
int id;
vector<int> A;
int Dep[MAXP+5];
bool vis[MAXP+5];
int Anc[MAXP+5][LOG+5];
void Build(int i,int fa,int dep){
Dep[i]=dep,vis[i]=1;
if(lch&&rch){
Anc[lch][0]=Anc[rch][0]=i;
Build(lch,i,dep+1);
Build(rch,i,dep+1);
K[i].l=K[lch].l,K[i].r=K[rch].r;
}
else{
K[i].l=K[i].r=++id;
A.push_back(H[K[i].id]);
}
}
#undef lch
#undef rch
int Query(int u,int lim,int kth){
for(int i=LOG;i>=0;i--)
if(Anc[u][i]&&K[Anc[u][i]].w<=lim)
u=Anc[u][i];
if(1<=kth&&kth<=K[u].r-K[u].l+1)
return T.Query(T.Root[K[u].r],1,T.N,K[u].r-K[u].l-kth+2,T.Root[K[u].l-1]);
return 0;
}
int main(){
N=read(),M=read(),Q=read();
for(int i=1;i<=N;i++)
Num[i]=H[i]=read();
for(int i=1;i<=M;i++){
E[i].u=read(),
E[i].v=read(),
E[i].w=read();
}
int cnt=0;
sort(Num+1,Num+N+1);
for(int i=1;i<=N;i++)
if(!ID.count(Num[i]))
Rev[ID[Num[i]]=++cnt]=Num[i];
for(int i=1;i<=N;i++)
H[i]=ID[H[i]];
//離散化
T.N=cnt;
cnt=N;
Init(2*N);
sort(E+1,E+M+1,cmp);
for(int i=1;i<=N;i++)
K[i].ch[0]=K[i].ch[1]=0,K[i].id=i;
for(int i=1;i<=M;i++){
int u=E[i].u,v=E[i].v;
int x=Find(u),y=Find(v);
if(x!=y){
++cnt;
K[cnt].ch[0]=x;
K[cnt].ch[1]=y;
K[cnt].w=E[i].w;
fa[x]=y,fa[y]=cnt;
}
}
for(int i=cnt;i>=1;i--)
if(!vis[i]){
int u=Find(i);
Build(u,-1,1);
}
for(int i=0;i<int(A.size());i++)
T.Insert(T.Root[i+1],1,T.N,A[i],T.Root[i]);
for(int j=1;j<=LOG;j++)
for(int i=1;i<=2*N;i++)
Anc[i][j]=Anc[Anc[i][j-1]][j-1];
int Ans=0;
while(Q--){
int u=read(),lim=read(),kth=read();
Ans=Rev[Query(u^Ans,lim^Ans,kth^Ans)];
printf("%d\n",Ans?Ans:-1);
}
}