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
无
Sample Output
无
HINT
【数据范围】
N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。
题解
这题超强,首先没样例差评,所以你得把强制在线去了然后找3545的样例测,3545还是权限题这题不是
3545我还是有点想法离线+并查集+线段树合并的,强制在线不会了。。
%啊
%到一个神奇的东西:Kruskal重构树
感谢popoqqq大爷的blog
简单来说,和LCT存边权差不多的道理。Kruskal建边的时候,不直接把两个连通块连起来,而是再拉一个点,给这个点一个点权,点权相当于边权。然后把这个点与这两个连通块的根连起来,于是这两个点之间的最大距离即为这两个点LCA的权值。
还有一些很不错的性质,比如这棵树是一棵二叉树,且满足大根堆的性质
这题的话,你可以预处理出来这棵重构树。然后对于一个点,把他向上倍增,找到一个最大且不大于给定的值的点,可以发现这个点的子树就是他所能到达的所有点。那么dfs序套主席树即可
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
struct edge{int x,y,c;}e[510000];
bool cmpx(edge n1,edge n2){return n1.c<n2.c;}
int col[410000],sum[410000];
struct LSnode{int y,p;}w[410000];int Rank[410000];
bool cmp(LSnode n1,LSnode n2){return n1.y<n2.y;}
struct trnode
{
int lc,rc,c;
}tr[6110000];int trlen;
void add(int &now,int l,int r,int p)
{
if(now==0)now=++trlen;
tr[now].c++;
if(l==r)return ;
int mid=(l+r)/2;
if(p<=mid)add(tr[now].lc,l,mid,p);
else add(tr[now].rc,mid+1,r,p);
}
int rt[410000];
void merge(int &x,int y)
{
if(x==0){x=y;return ;}
if(y==0)return ;
tr[x].c+=tr[y].c;
merge(tr[x].lc,tr[y].lc);
merge(tr[x].rc,tr[y].rc);
}
struct node
{
int x,y,next;
}a[510000];int len,last[211000];
void ins(int x,int y)
{
len++;
a[len].x=x;a[len].y=y;
a[len].next=last[x];last[x]=len;
}
int n,m,q,fa[210000],H[210000],cnt,bin[25];
int findfa(int x){return fa[x]!=x?fa[x]=findfa(fa[x]):fa[x];}
int f[210000][25],dep[210000];
int l[210000],r[210000],dfn;
void pre_tree_node(int x)
{
for(int i=1;bin[i]<=dep[x];i++)f[x][i]=f[f[x][i-1]][i-1];
if(col[x]!=0)add(rt[dfn+1],1,n,Rank[x]);
merge(rt[dfn+1],rt[dfn]);
l[x]=++dfn;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=f[x][0])
{
f[y][0]=x;
dep[y]=dep[x]+1;
pre_tree_node(y);
}
}
r[x]=dfn;
}
int lastans,tt;
int findKth(int x,int y,int l,int r,int K)
{
if(K>tr[y].c-tr[x].c)return -1;
if(l==r)return w[l].y;
int lcx=tr[x].lc,rcx=tr[x].rc,lcy=tr[y].lc,rcy=tr[y].rc;
int c=tr[rcy].c-tr[rcx].c;
int mid=(l+r)/2;
if(K<=c)return findKth(rcx,rcy,mid+1,r,K);
else return findKth(lcx,lcy,l,mid,K-c);
}
int sol(int u,int p,int k)
{
int X=u;
for(int i=22;i>=0;i--)
if(bin[i]<dep[X] && sum[f[X][i]]<=p)X=f[X][i];
return findKth(rt[l[X]-1],rt[r[X]],1,tt,k);
}
int main()
{
bin[0]=1;
for(int i=1;i<=22;i++)bin[i]=bin[i-1]*2;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++){scanf("%d",&col[i]);w[i].y=col[i];w[i].p=i;}
sort(w+1,w+1+n,cmp);
tt=1;Rank[w[1].p]=1;
for(int i=2;i<=n;i++)
{
tt++;
Rank[w[i].p]=tt;
}
for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].c);
sort(e+1,e+1+m,cmpx);
for(int i=1;i<=n;i++)fa[i]=i,H[i]=i;
int cnt=n;
for(int i=1;i<=m;i++)
{
int p=findfa(e[i].x),q=findfa(e[i].y);
if(p!=q)
{
cnt++;
ins(cnt,H[p]);ins(cnt,H[q]);sum[cnt]=e[i].c;
fa[p]=q;H[q]=cnt;
}
}
for(int i=1;i<=n;i++)
{
fa[i]=findfa(fa[i]);
if(fa[i]==i)
{
int u=H[i];
f[u][0]=0;dep[u]=1;pre_tree_node(u);
}
}
lastans=0;
while(q--)
{
int u,x,k;
scanf("%d%d%d",&u,&x,&k);
if(lastans!=-1)u^=lastans,x^=lastans,k^=lastans;
lastans=sol(u,x,k);
printf("%d\n",lastans);
}
return 0;
}