bzoj 3545: [ONTAK2010]Peaks (splay啓發式合併)

3545: [ONTAK2010]Peaks

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1750  Solved: 472
[Submit][Status][Discuss]

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,表示一組詢問。

Output

對於每組詢問,輸出一個整數表示答案。

Sample Input

10 11 4
1 2 3 4 5 6 7 8 9 10
1 4 4
2 5 3
9 8 2
7 8 10
7 1 4
6 7 1
6 4 8
2 1 5
10 8 10
3 4 7
3 4 6
1 5 2
1 5 6
1 5 8
8 9 2

Sample Output

6
1
-1
8


HINT

【數據範圍】

N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。

Source

By Sbullet



明明記得這題放過題解,找不到了,那就再放一次。。。


對於每個並查集開一顆splay,合併並查集的同時啓發式合併splay


啓發式合併是什麼意思呢,小的splay暴力插入大的中.......


代碼:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<climits>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define N 500010
#define M 2500010
using namespace std;
inline int read()
{
	int x=0,f=1;char ch;
	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,ans[N];
int tr[M][2],fa[M],size[M];
int root[N],v[M],sz;
inline void pushup(int k){size[k]=size[tr[k][0]]+size[tr[k][1]]+1;}
inline void rotate(int x,int &k)
{
	int y=fa[x],z=fa[y],l,r;
	l=tr[y][1]==x;r=l^1;
	if(k==y)k=x;
	else tr[z][tr[z][1]==y]=x;
	fa[x]=z,fa[y]=x,fa[tr[x][r]]=y;
	tr[y][l]=tr[x][r],tr[x][r]=y;
	pushup(y);pushup(x);
}
inline void splay(int x,int &k)
{
	while(x!=k)
	{
		int y=fa[x],z=fa[y];
		if(y!=k)
		{
			if(tr[y][0]==x^tr[z][0]==y)
				rotate(x,k);
			else rotate(y,k);
		}rotate(x,k);
	}
}
inline int find_k(int k,int rk)
{
	int l=tr[k][0],r=tr[k][1];
	if(size[r]+1==rk)return v[k];
	else if(size[r]>=rk)return find_k(r,rk);
	else return find_k(l,rk-size[r]-1);
}
int t1,t2;
inline void ins(int &k,int x,int last,int &rt)
{
	if(!k){k=++sz;fa[k]=last,size[k]=1,v[k]=x;splay(k,rt);return;}
	else if(v[k]>=x)ins(tr[k][0],x,k,rt);
	else ins(tr[k][1],x,k,rt);
}
inline void merge(int k,int &rt)
{
	if(!k)return;
	merge(tr[k][0],rt);
	merge(tr[k][1],rt);	
	ins(rt,v[k],0,rt);
}


int pre[N],h[N];
int find(int x){return x==pre[x]?x:pre[x]=find(pre[x]);} 
inline void work(int a,int b)
{
	int rb=root[b],ra=root[a];
	if(size[root[b]]>size[root[a]])
	 	swap(a,b);pre[b]=a;
	merge(root[b],root[a]);
}
struct edge{int x,y,c;}e[M];
bool operator < (edge a,edge b){return a.c<b.c;}
struct qry{int v,x,k,id;}ak[M]; 
bool operator < (qry a,qry b){return a.x<b.x;}
void init()
{
	n=read(),m=read(),q=read();
	for(int i=1;i<=n;i++)h[i]=read();
	for(int i=1;i<=n;i++)
	{
		pre[i]=i;
		ins(root[i],h[i],0,i);
	}
	for(int i=1;i<=m;i++)
	{
		e[i].x=read();
		e[i].y=read();
		e[i].c=read();
	}sort(e+1,e+1+m);
	for(int i=1;i<=q;i++)
	{
		ak[i].v=read();
		ak[i].x=read();
		ak[i].k=read();
		ak[i].id=i;
	}sort(ak+1,ak+1+q);
}
int main()
{
//	freopen("in.txt","r",stdin);
//	freopen("my.txt","w",stdout);
	init();
	int i=0,j=1;
	for(i=1;i<=q;i++)
	{
		while(e[j].c<=ak[i].x&&j<=m)
		{
			int a=e[j].x,b=e[j].y;
			int fa=find(a),fb=find(b);
			if(fa!=fb)work(fa,fb);j++;
		}int t=find(ak[i].v);
		if(size[root[t]]<ak[i].k)ans[ak[i].id]=-1;
		else ans[ak[i].id]=find_k(root[t],ak[i].k);
	}for(int i=1;i<=q;i++)printf("%d\n",ans[i]);
}



發佈了143 篇原創文章 · 獲贊 22 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章