题意:
给出一个n个点m条边的无向图,点和边都有权值;
q次询问从某个点出发,经过不超过x的权值的边能到达的第k大点权值;
1<=n<=100000,1<=m,q<=500000;
权值<=10^9;
题解:
题意略鬼畜。。。
首先能看出来走的边一定是在最小生成树上,然后这并没有什么卵用;
不过至少提供了一点思路,剩下思路就是将询问离线了;
离线之后可以做到一次遍历边表,顺便的求出所有的答案值;
对于每次的询问,答案就是那个点所在连通块的k大值;
这里我用Treap的启发式合并实现;
似乎是第一次写启发式合并的题(并查集不算= =),不过实现似乎挺诡异了点。。
时间复杂度O(nlog^2n);
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
using namespace std;
struct edge
{
int x,y,v;
friend bool operator <(edge a,edge b)
{
return a.v<b.v;
}
}E[N*5];
struct Query
{
int x,v,k,no;
friend bool operator <(Query a,Query b)
{
return a.v<b.v;
}
}Q[N*5];
int ans[N*5];
int ls[N],rs[N],val[N],fa[N],size[N],rnd[N];
void Pushup(int x)
{
size[x]=size[ls[x]]+size[rs[x]]+1;
}
int find(int x,int k)
{
if(k<=0||k>size[x])
return -1;
if(size[ls[x]]>=k)
return find(ls[x],k);
else if(size[ls[x]]+1==k)
return val[x];
else
return find(rs[x],k-size[ls[x]]-1);
}
void lturn(int &x)
{
int p=rs[x];
rs[x]=ls[p];
ls[p]=x;
fa[rs[x]]=x;
fa[p]=fa[x];
fa[x]=p;
size[p]=size[x];
Pushup(x);
x=p;
}
void rturn(int &x)
{
int p=ls[x];
ls[x]=rs[p];
rs[p]=x;
fa[ls[x]]=x;
fa[p]=fa[x];
fa[x]=p;
size[p]=size[x];
Pushup(x);
x=p;
}
void Insert(int &x,int t)
{
if(!x)
{
x=t;
return ;
}
size[x]++;
if(val[t]>val[x])
{
Insert(ls[x],t);
fa[ls[x]]=x;
if(rnd[ls[x]]>rnd[x])
rturn(x);
}
else
{
Insert(rs[x],t);
fa[rs[x]]=x;
if(rnd[rs[x]]>rnd[x])
lturn(x);
}
}
void Link(int &x,int &y)
{
if(!x||!y) return ;
fa[ls[x]]=fa[rs[x]]=0;
Link(ls[x],y);
Link(rs[x],y);
ls[x]=rs[x]=0;
size[x]=1;
Insert(y,x);
}
int query(int x,int k)
{
while(fa[x]) x=fa[x];
return find(x,k);
}
int main()
{
srand(140142);
int n,m,q,i,j,k,x,y,fx,fy;
scanf("%d%d%d",&n,&m,&q);
for(i=1;i<=n;i++)
{
scanf("%d",val+i);
size[i]=1;
rnd[i]=rand();
}
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&E[i].x,&E[i].y,&E[i].v);
}
for(i=1;i<=q;i++)
{
scanf("%d%d%d",&Q[i].x,&Q[i].v,&Q[i].k);
Q[i].no=i;
}
sort(E+1,E+m+1);
sort(Q+1,Q+q+1);
for(i=1,j=0;i<=q;i++)
{
while(j<m&&E[j+1].v<=Q[i].v)
{
j++;
while(fa[E[j].x]) E[j].x=fa[E[j].x];
while(fa[E[j].y]) E[j].y=fa[E[j].y];
if(E[j].x!=E[j].y)
{
if(size[E[j].x]>size[E[j].y])
swap(E[j].x,E[j].y);
Link(E[j].x,E[j].y);
}
}
ans[Q[i].no]=query(Q[i].x,Q[i].k);
}
for(i=1;i<=q;i++)
printf("%d\n",ans[i]);
return 0;
}