1. 程式人生 > >「BZOJ3545」「ONTAK2010」 Peaks - Splay啟發式合併

「BZOJ3545」「ONTAK2010」 Peaks - Splay啟發式合併

題目描述

在Bytemountains有N座山峰,每座山峰有它的高度h_i。有些山峰之間有雙向道路相連,共M條路徑,每條路徑有一個困難值,這個值越大表示越難走,現在有Q組詢問,每組詢問詢問從點v開始只經過困難值小於等於x的路徑所能到達的山峰中第k高的山峰,如果無解輸出-1。

輸入格式

第一行三個數N,M,Q。

第二行N個數,第i個數為h_i。

接下來M行,每行3個數a b c,表示從a到b有一條困難值為c的雙向路徑。

接下來Q行,每行三個數v x k,表示一組詢問。

輸出格式

對於每組詢問,輸出一個整數表示所求山峰的高度。

資料範圍

N<=105

, M,Q<=5*105,hi,c,x<=109

分析

由於題目沒有要求要線上,於是考慮離線。讀入所有的邊和詢問,將邊和詢問分別按照 c c x x 從小到大排序。然後對每個點開 N

N S p l a y Splay ,對於每個詢問,將所有 c
x c\le x
的邊的兩頂點的 S p l a y Splay 合併起來,然後在 v v 所在的 S p l a y Splay 中查詢第 K K 大。由於先排序了的,所以順序處理每個詢問,在上一個詢問的基礎上合併。

程式碼

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N=100005,M=500005;
typedef long long LL;
struct Edge {
	int x,y,w;
	bool operator<(const Edge&e) const {
		return w<e.w;
	}
}e[M];
struct Query {
	int v,x,k,id;
	bool operator<(const Query&e) const {
		return x<e.x;
	}
}q[M];
int n,m,Q,sz[N];
int v[N],f[N],c[N][2],ans[M];
int fa[N],pt[N],st[N],top;
void Pushup(int x) {if (x) sz[x]=sz[c[x][0]]+sz[c[x][1]]+1;}
int Getf(int x) {return fa[x]==x?x:fa[x]=Getf(fa[x]);}//用並查集判斷聯通性 
void Rotate(int x) {
	int y=f[x],z=f[y];
	int k=c[y][1]==x,kk=c[z][1]==y;
	c[y][k]=c[x][k^1];
	f[c[x][k^1]]=y;
	c[x][k^1]=y;
	f[y]=x;
	if (z) c[z][kk]=x;
	f[x]=z;
	Pushup(y);
	Pushup(x);
}
void Splay(int x) {
	while (f[x]) {
		int y=f[x],z=f[y];
		if (z) {
			if ((c[y][1]==x)^(c[z][1]==y)) Rotate(x);
			else Rotate(y);
		}
		Rotate(x);
	}
}
void Insert(int p,int q) {
	while (1) {
		sz[p]++;
		int nxt=(v[q]<=v[p]?0:1);
		if (!c[p][nxt]) {
			c[p][nxt]=q;
			f[q]=p;
			c[q][0]=c[q][1]=0;
			sz[q]=1;
			Splay(q);
			return;
		}
		p=c[p][nxt];
	}
}//以上Splay基本操作
void Dfs(int x) {
	if (!x) return;
	Dfs(c[x][0]);
	st[++top]=x;
	Dfs(c[x][1]);
}
void Merge(int x,int y) {
	int fx=Getf(x);
	int fy=Getf(y);
	if (fx==fy) return;
	fa[fy]=fx;
	Splay(x);
	Splay(y);
	if (sz[x]<sz[y]) swap(x,y);//啟發式,將小的向大的合併 
	Dfs(y);//獲得中序遍歷序,據說可以減少時間複雜度
	st[top+1]=x;
	while (top) {
		Insert(st[top+1],st[top]);//一個個插入
		top--;
	}
}
int Kth(int p,int k) {
	Splay(p);
	if (k>sz[p]) return -1;
	k=sz[p]-k+1;
	while (1) {
		if (sz[c[p][0]]+1==k) return v[p];
		if (sz[c[p][0]]>=k) p=c[p][0];
		else {
			k-=sz[c[p][0]]+1;
			p=c[p][1];
		}
	}
}
int main() {
	scanf("%d%d%d",&n,&m,&Q);
	for (int i=1;i<=n;i++) scanf("%d",&v[i]),fa[i]=i,sz[i]=1;//讀入並初始化
	for (int i=1;i<=m;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
	for (int i=1;i<=Q;i++) scanf("%d%d%d",&q[i].v,&q[i].x,&q[i].k),q[i].id=i;
	sort(e+1,e+m+1);
	sort(q+1,q+Q+1);
	int ei,qi;
	ei=qi=1;
	while (qi<=Q) {
		while (ei<=m&&e[ei].w<=q[qi].x) {
			Merge(e[ei].x,e[ei].y);
			ei++;
		}
		ans[q[qi].id]=Kth(q[qi].v,q[qi].k);
		qi++;
	}
	for (int i=1;i<=Q;i++) printf("%d\n",ans[i]);
	return 0;
}