转载来自于:http://blog.csdn.net/PoPoQQQ/article/details/41348785
弱真不知道这个题解怎么写。
题目大意:同3545 强制在线
3545题解传送门:http://blog.csdn.net/popoqqq/article/details/40660953
强制在线没法排序 启发式合并也就用不了了
Kruskal重构树是个挺好玩的东西 可以拿来处理一些最小生成树的边权最值问题
这里我们Kruskal连边时并不直接连边 而是新建一个节点ext 将两个点所在子树都连到ext的儿子上
比如说样例的树就建成了这样
图中红色的是原图的边权,黑色的是原图上的点
这样生成的树有一些十分优美的性质:
1.二叉树(好吧这题意义不大)
2.原树与新树两点间路径上边权(点权)的最大值相等
3.子节点的边权小于等于父亲节点(大根堆)
4.原树中两点之间路径上边权的最大值等于新树上两点的LCA的点权
于是对于每个询问 我们从这个询问向上倍增寻找深度最小的点权小于等于x的点 易证这个节点的子树就是v所能到达的所有点
DFS序+可持久化线段树直接搞就行
代码(本人):
#include<cstdio>
#include<cstring>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<vector>
#include<bitset>
#include<set>
#include<queue>
#include<stack>
#include<map>
#include<cstdlib>
#include<cmath>
#define PI 2*asin(1.0)
#define LL long long
#define pb push_back
#define pa pair<int,int>
#define clr(a,b) memset(a,b,sizeof(a))
#define lson lr<<1,l,mid
#define rson lr<<1|1,mid+1,r
#define bug(x) printf("%d++++++++++++++++++++%d\n",x,x)
#define key_value ch[ch[root][1]][0]
const int MOD = 1000000007;
const int N = 2e5+15;
const int maxn = 5e5+1000;
const int letter = 130;
const int INF = 1e17;
const double pi=acos(-1.0);
const double eps=1e-8;
using namespace std;
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;
}
int n,m,q,h[N],val[N],father[N],fnp,ps[N];
int tot,head[N],deep[N],fa[N][20],dis[N][20];
int l[N],r[N],top,dfn[N],vis[N],bin[20];
int root[N],ls[N*20],rs[N*20],sum[N*20],siz;
struct node{
int x,y,val;
bool operator <(const node &a)const{
return val<a.val;
}
}qu[maxn];
struct edges{
int to,next;
}e[N];
int Find(int x){
if(x==father[x]) return x;
return father[x]=Find(father[x]);
}
void init(){
siz=top=tot=0,clr(head,-1);
for(int i=1;i<=2*n;i++) father[i]=i;
bin[0]=1;
for(int i=1;i<=18;i++) bin[i]=bin[i-1]<<1;
}
int findmax(int x,int val){
for(int i=18;i>=0;i--) if(deep[x]>=bin[i]&&dis[x][i]<=val) x=fa[x][i];
return x;
}
void addedges(int u,int v){
e[tot].to=v,e[tot].next=head[u],head[u]=tot++;
}
void dfs(int x){
vis[x]=1;
dfn[++top]=x,l[x]=top;
for(int i=head[x];i!=-1;i=e[i].next){
int to=e[i].to;
deep[to]=deep[x]+1;
fa[to][0]=x;
dis[to][0]=val[x];
dfs(to);
}
r[x]=top;
}
void insert(int l,int r,int x,int &y,int v){
y=++siz;
sum[y]=sum[x]+1;
if(l==r) return;
ls[y]=ls[x],rs[y]=rs[x];
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);
}
int query(int l,int r,int a,int b,int k){
if(l==r) return l;
int mid=(l+r)>>1;
if(sum[ls[b]]-sum[ls[a]]>=k) return query(l,mid,ls[a],ls[b],k);
else return query(mid+1,r,rs[a],rs[b],k-(sum[ls[b]]-sum[ls[a]]));
}
int main(){
n=read(),m=read(),q=read();
fnp=n;///sum node
for(int i=1;i<=n;i++) h[i]=read(),ps[i]=h[i];
sort(ps+1,ps+n+1);
for(int i=1;i<=n;i++) h[i]=lower_bound(ps+1,ps+n+1,h[i])-ps;
for(int i=0;i<m;i++){
qu[i].x=read(),qu[i].y=read(),qu[i].val=read();
}
sort(qu,qu+m);
init();
/// kruskal chonggou
for(int i=0;i<m;i++){
int xx=Find(qu[i].x),yy=Find(qu[i].y);
if(xx!=yy){
fnp++;
father[xx]=father[yy]=fnp;
addedges(fnp,xx),addedges(fnp,yy);
val[fnp]=qu[i].val;
}
}/// kruskal tree
for(int i=1;i<=n;i++){
if(!vis[i]) dfs(Find(i));
}
for(int j=1;j<=18;j++)
for(int i=1;i<=fnp;i++){
fa[i][j]=fa[fa[i][j-1]][j-1];
dis[i][j]=max(dis[i][j-1],dis[fa[i][j-1]][j-1]);
}
for(int i=1;i<=top;i++){ ///dfs xu
int x=dfn[i];
if(x<=n) insert(1,n,root[i-1],root[i],h[x]);
else root[i]=root[i-1];
}
int ans=-1;
while(q--){
int x,v,k,aim;
x=read(),v=read(),k=read();
if(ans!=-1) x=x^ans,v=v^ans,k=k^ans;
aim=findmax(x,v);/// root
int la=root[l[aim]],ra=root[r[aim]];
if(sum[ra]-sum[la]<k) ans=-1;
else ans=query(1,n,la,ra,sum[ra]-sum[la]+1-k),ans=ps[ans];
printf("%d\n",ans);
}
return 0;
}