BZOJ3551 Peaks 加强版 【kruskal重构树】【主席树】

题目链接:http://darkbzoj.tk/problem/3551

题解:
对原图求一遍kruskal重构树,考虑在重构树上倍增,求出深度最小的点权 ≤ k \le k k的点(显然不是原图上的点),然后只需要求子树第k大,这显然可以主席树解决

代码:

// by Balloons
#include 
#include 
#include 
#include 
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1e9, maxn=5e5+5;

int n,m,q;
int a[maxn],b[maxn],nn,w[maxn];
struct edge{
	int x,y,v;
	bool operator < (const edge b) const {
		return v<b.v;
	}
}e[maxn];
struct edges{
	int to,nxt;
}ed[maxn << 1];
int head[maxn], ecnt=0;
int fa[maxn],totp,f[maxn][22];
int len[maxn][2], dfs_clock;

int find(int x){return fa[x] == x?fa[x]:fa[x] = find(fa[x]);}
void add(int x,int y){
	ed[++ ecnt].to = y;ed[ecnt].nxt = head[x];head[x] = ecnt;
}

struct segm{
	int ls,rs,v;
}se[maxn << 5];
int curs = 0,rt[maxn];

void update(int &num,int now,int x,int y,int k){
	num = ++ curs;se[num] = se[now];++ se[num].v;
	if(x == y)return ;
	int mid=x+y>>1;
	if(k<=mid)update(se[num].ls,se[now].ls,x,mid,k);
	else update(se[num].rs,se[now].rs,mid+1,y,k);
}

int query(int num,int now,int k,int x,int y){
	if(x == y)return x;
	int mid=x+y>>1;
	int vv = se[se[now].rs].v - se[se[num].rs].v;
	if(k <= vv)return query(se[num].rs,se[now].rs,k,mid+1,y);
	else return query(se[num].ls,se[now].ls,k-vv,x,mid);
}

void kruskal(){
	totp = n;
	sort(e+1,e+m+1);
	for(int i=1;i<=2*n;i++)fa[i] = i;
	
	int inmst = 0;
	for(int i=1;i<=m;i++){
		int x = e[i].x, y = e[i].y;
		int fx = find(x), fy = find(y);
		if(fx == fy)continue;
		fa[fy] = fa[fx] = ++ totp;
		w[totp] = e[i].v;
		add(totp,fx);add(fx,totp);
		add(totp,fy);add(fy,totp);
		
		++ inmst;
		if(inmst == n-1)break; 
	}
}

void dfs(int x,int fat=0){
	f[x][0] = fat;
	len[x][0] = dfs_clock;
	
	int isleaf = 0;
	for(int i=head[x];~i;i=ed[i].nxt){
		int u=ed[i].to;
		if(u == fat)continue;
		dfs(u,x);
		isleaf = 1;
	}
	if(!isleaf){
		len[x][0] = ++dfs_clock;
		update(rt[dfs_clock],rt[dfs_clock-1],1,nn,a[x]);
		return ;
	}
	
	len[x][1] = dfs_clock;
}

int main(){
//	freopen("Luogu4197.in","r",stdin);
	memset(head,-1,sizeof head);
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]), b[i] = a[i];
	sort(b+1,b+n+1);
	nn = unique(b+1,b+n+1) - (b+1);
	for(int i=1;i<=n;i++)a[i] = lower_bound(b+1,b+nn+1,a[i]) - b;

	for(int i=1;i<=m;i++){
		int x,y,z;scanf("%d%d%d",&x,&y,&z);
		e[i] = (edge){x,y,z};
	}
	kruskal();
	dfs(totp); 
	for(int j=1;j<=20;j++){
		for(int i=1;i<=totp;i++)f[i][j] = f[f[i][j-1]][j-1];
	}
	int lstans = -1;
	while(q --){
		int x,d,k;scanf("%d%d%d",&x,&d,&k);
		if(~lstans)x ^= lstans, d ^= lstans, k ^= lstans;
		for(int i=20;i>=0;i--){
			if(f[x][i] && w[f[x][i]] <= d)x = f[x][i];
		}
		if(len[x][1] - len[x][0] < k){puts("-1");lstans = -1;continue;}
		printf("%d\n",lstans = b[query(rt[len[x][0]], rt[len[x][1]],k,1,nn)]);
	}

	return 0;
}

你可能感兴趣的:(【解题报告】,====并查集&差分,====主席树)