题目大意:同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 <algorithm>
#define M 200200
using namespace std;
struct Segtree{
Segtree *ls,*rs;
int num;
void* operator new (size_t size,Segtree *_,Segtree *__,int ___);
}*tree[M],*mempool,*C;
struct edge{
int x,y,f;
bool operator < (const edge &Y) const
{
return f < Y.f ;
}
}edges[500500];
struct abcd{
int to,next;
}table[M];
int head[M],tot;
int n,m,q,ans;
int a[M],fa[M][20],dis[M][20],belong[M];
int seq[M],l[M],r[M],cnt;
void* Segtree :: operator new (size_t size,Segtree *_,Segtree *__,int ___)
{
if(C==mempool)
{
C=new Segtree[1<<15];
mempool=C+(1<<15);
}
C->ls=_;
C->rs=__;
C->num=___;
return C++;
}
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
int Find(int x)
{
if(!belong[x]||belong[x]==x)
return belong[x]=x;
return belong[x]=Find(belong[x]);
}
void Kruskal()
{
int i;
sort(edges+1,edges+m+1);
for(i=1;i<=m;i++)
{
int x=Find(edges[i].x);
int y=Find(edges[i].y);
if(x==y) continue;
belong[x]=belong[y]=++n;
fa[x][0]=fa[y][0]=n;
dis[x][0]=dis[y][0]=edges[i].f;
Add(n,x);Add(n,y);
}
}
void DFS(int x)
{
int i;
seq[l[x]=++cnt]=a[x];
for(i=head[x];i;i=table[i].next)
DFS(table[i].to);
r[x]=cnt;
}
Segtree* Build_Tree(Segtree *p,int x,int y,int val)
{
int mid=x+y>>1;
if(x==y) return new (0x0,0x0,p->num+1) Segtree;
if(val<=mid) return new (Build_Tree(p->ls,x,mid,val),p->rs,p->num+1) Segtree;
else return new (p->ls,Build_Tree(p->rs,mid+1,y,val),p->num+1) Segtree;
}
int Get_Kth(Segtree *p1,Segtree *p2,int x,int y,int k)
{
int mid=x+y>>1;
if(x==y) return mid;
int temp=p2->rs->num-p1->rs->num;
if(k<=temp) return Get_Kth(p1->rs,p2->rs,mid+1,y,k);
else return Get_Kth(p1->ls,p2->ls,x,mid,k-temp);
}
int Get_Root(int x,int y)
{
int j;
for(j=19;~j;j--)
if( fa[x][j] && dis[x][j]<=y )
x=fa[x][j];
return x;
}
int main()
{
int i,j,v,x,k;
cin>>n>>m>>q;
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=m;i++)
scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].f);
Kruskal();
for(j=1;j<=19;j++)
for(i=1;i<=n;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]);
DFS(n);
tree[0]=new (0x0,0x0,0) Segtree;
tree[0]->ls=tree[0]->rs=tree[0];
for(i=1;i<=n;i++)
tree[i]=Build_Tree(tree[i-1],0,1000000000,seq[i]);
for(i=1;i<=q;i++)
{
scanf("%d%d%d",&v,&x,&k);
x^=ans;v^=ans;k^=ans;
int root=Get_Root(v,x);
if(r[root]-l[root]+1<k)
{
puts("-1");
ans=0;
continue;
}
ans=Get_Kth(tree[l[root]-1],tree[r[root]],0,1000000000,k);
if(!ans)
{
puts("-1");
continue;
}
printf("%d\n",ans);
}
}