Description
【题目描述】同3545
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
同3545
Sample Input
Sample Output
HINT
【数据范围】同3545
题解:既然强制在线。那么我们就无法离线然后平衡树+启发式合并了。
考虑做最小生成树。
合并两个点的时候我们不直接合并。而是新建一个点。然后把两个点连向他,并设为两个点的父亲。
这个点的权值我们设成连接这两个点的边的边权。
这样可以新建出来一棵树。
这棵树首先肯定是个大根堆。
这棵树上的两点间的lca的权值等于原图中两点间路径上的边的最大值.
然后对于每次询问我们可以倍增出最浅的权值不超过给定值的那个点.那个点所控制的子树的所有叶子节点就是能到达的所有点。
主席树+dfs序查询即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200010
using namespace std;
int cnt,point[N],next[N],s[N],n,m,p,h[N],f[N],t,v[N],vis[N],top,fa[N][20],mx[N][20],bg[N],ed[N];
int deep[N],q[N*3],root[N*3],ls[N*25],rs[N*25],sum[N*25],sz,ans(-1);
struct use{int st,en,v;}e[N],b[N*3];
bool cmp(use a,use b){return a.v<b.v;}
void add(int x,int y){next[++cnt]=point[x];point[x]=cnt;e[cnt].en=y;}
int fd(int x){return x==f[x]?x:f[x]=fd(f[x]);}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void dfs(int x){
q[++top]=x;vis[x]=1;
for (int i=1;(1<<i)<=deep[x];i++)
fa[x][i]=fa[fa[x][i-1]][i-1],mx[x][i]=max(mx[x][i-1],mx[fa[x][i-1]][i-1]);
for (int i=point[x];i;i=next[i]){
fa[e[i].en][0]=x;mx[e[i].en][0]=v[x];
deep[e[i].en]=deep[x]+1;dfs(e[i].en);
}
if (x>n) q[++top]=x;
}
void insert(int l,int r,int &x,int y,int v){
x=++sz;sum[x]=sum[y]+1;
if(l==r)return;
ls[x]=ls[y];rs[x]=rs[y];
int mid=(l+r)>>1;
if(v<=mid)insert(l,mid,ls[x],ls[y],v);else insert(mid+1,r,rs[x],rs[y],v);
}
void pre(){
t=n;sort(b+1,b+m+1,cmp);
for (int i=1;i<=m;i++){
int r1=fd(b[i].st),r2=fd(b[i].en);
if (r1!=r2){t++;f[r1]=f[r2]=t;v[t]=b[i].v;add(t,r2);add(t,r1);if (t==2*n-1) break;}
}
for (int i=1;i<=n;i++) if (!vis[i]) dfs(fd(i));
for (int i=1;i<=top;i++){
int t=q[i];
if (t<=n)insert(1,n,root[i],root[i-1],h[t]);
else{
root[i]=root[i-1];
if (!bg[t]) bg[t]=i;else ed[t]=i;
}
}
}
int find(int x,int v){
for(int i=17;i>=0;i--)if(deep[x]>=(1<<i)&&mx[x][i]<=v)x=fa[x][i];
return x;
}
int query(int l,int r,int x,int y,int rk){
if(l==r)return l;
int mid=(l+r)>>1;
if(sum[ls[y]]-sum[ls[x]]>=rk)return query(l,mid,ls[x],ls[y],rk);
else return query(mid+1,r,rs[x],rs[y],rk-sum[ls[y]]+sum[ls[x]]);
}
void work(){
int x,v,k;
for(int i=1;i<=p;i++){
v=read();x=read();k=read();if(ans!=-1)v^=ans,x^=ans,k^=ans;
int t=find(v,x);
int l=root[bg[t]],r=root[ed[t]];
if(sum[r]-sum[l]<k) ans=-1;
else ans=s[query(1,n,l,r,sum[r]-sum[l]-k+1)];
printf("%d\n",ans);
}
}
int main(){
n=read();m=read();p=read();
for(int i=1;i<=n;i++) h[i]=read(),s[i]=h[i];
sort(s+1,s+n+1);
for(int i=1;i<=n;i++) h[i]=lower_bound(s+1,s+n+1,h[i])-s;
for(int i=1;i<=n*2;i++) f[i]=i;
for (int i=1;i<=m;i++) b[i].st=read(),b[i].en=read(),b[i].v=read();
pre();work();
}