BZOJ 3551: [ONTAK2010]Peaks加强版 [Kruskal重构树 dfs序 主席树]

3551: [ONTAK2010]Peaks加强版

题意:带权图,多组询问与一个点通过边权\(\le lim\)的边连通的点中点权k大值,强制在线


PoPoQQQ大爷题解传送门


说一下感受:
容易发现一定选最小生成树上的边,然后用到了一个神奇的东西

Kruskal重构树

  • 进行Kruskal过程中,每条边用一个点代替,左右儿子分别是连的两个点的当前的父亲
    这样就形成了一棵树,叶子都是原图上的点,其他都是原图上的边
  • 深度越小的点对应的边权值越大
  • 两点路径上的权值不变
  • 这样的话,与一个点通过权值\(\le lim\)的边连通,就是这个点权值\(\le lim\)的父亲对应的子树中的点
    对dfs序建主席树就行了


    实现上我只将原图中的点加入了dfs序


    该死离散化写错了WA了半小时
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define lc(x) t[x].l
#define rc(x) t[x].r
const int N=2e5+5, M=5e5+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

int n, m, Q, val[N], tot, u, lim, k, mp[N];
struct meow{
	int u,v,w;
	bool operator <(const meow &r) const{return w<r.w;}
}a[M];
namespace ufs{
	int fa[N];
	int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
}
struct edge{int v,ne;}e[N<<1];
int cnt, h[N];
inline void ins(int u, int v) {
	e[++cnt]=(edge){v, h[u]}; h[u]=cnt;
}
void Kruskal() {
	using ufs::fa; using ufs::find;
	sort(a+1, a+1+m);
	int cnt=0;
	for(int i=1; i<=m; i++) { 
		int u=a[i].u, v=a[i].v, w=a[i].w;
		int x=find(u), y=find(v);
		if(x==y) continue;

		val[++tot]=w; //printf("hey %d %d  %d  %d\n",x,y,tot,val[tot]);
		ins(tot, x); ins(tot, y);
		fa[x]=fa[y]=fa[tot]=tot;
		if(++cnt == n-1) break;
	}
}

int deep[N], dfc, ver[N], L[N], R[N];
int fa[N][20];
void dfs(int u) { //printf("dfs %d %d\n",u,val[u]);
	if(u<=n) ver[++dfc]=u;
	L[u]=dfc;
	for(int i=1; (1<<i)<=deep[u]; i++) 
		fa[u][i] = fa[ fa[u][i-1] ][i-1];
	for(int i=h[u];i;i=e[i].ne)
		if(e[i].v != fa[u][0]) {
			fa[e[i].v][0]=u;
			deep[e[i].v]=deep[u]+1;
			dfs(e[i].v);
		}
	R[u]=dfc;
}

struct ChairTree{
	struct meow{int l,r,size;}t[N*30];
	int sz, root[N];
	void insert(int &x, int l, int r, int p) {
		t[++sz]=t[x]; x=sz;
		t[x].size++;
		if(l==r) return;
		int mid=(l+r)>>1;
		if(p<=mid) insert(t[x].l, l, mid, p);
		else insert(t[x].r, mid+1, r, p);
	}
	void build() { 
		for(int i=1; i<=n; i++) root[i]=root[i-1], insert(root[i], 1, *mp, val[ver[i]]);// printf("%d ",ver[i]);puts("");
	}
	int kth(int x, int y, int k) { //printf("kth %d %d %d\n",x,y,k);
		x=root[x]; y=root[y];
		int all = t[y].size-t[x].size; //printf("xy %d %d %d\n",x,y,all);
		if(k>all) return -1;
		k = all-k+1;
		int l=1, r=*mp;
		while(l!=r) {
			int lsize = t[lc(y)].size - t[lc(x)].size, mid=(l+r)>>1;
			if(k<=lsize) x=lc(x), y=lc(y), r=mid;
			else x=rc(x), y=rc(y), l=mid+1, k-=lsize;
		}
		return l;
	}
}C;
int main() {
	freopen("in","r",stdin);
	n=read(); m=read(); Q=read(); tot=n;
	for(int i=1; i<=n; i++) val[i]=mp[i]=read(), ufs::fa[i]=i;
	val[0]=1e9+5;
	for(int i=1; i<=m; i++) a[i].u=read(), a[i].v=read(), a[i].w=read();
	Kruskal();
	dfs(tot);
	sort(mp+1, mp+1+n); mp[0]=unique(mp+1, mp+1+n)-mp-1;
	for(int i=1; i<=n; i++) val[i] = lower_bound(mp+1, mp+1+mp[0], val[i])-mp;
	C.build();
	int ans=0;
	for(int i=1; i<=Q; i++) {
		if(ans==-1) ans=0;
		u=read()^ans, lim=read()^ans, k=read()^ans;
		//u=read();lim=read();k=read();
		for(int i=16; i>=0; i--) if(val[fa[u][i]]<=lim) u=fa[u][i];
		ans = C.kth(L[u], R[u], k);
		if(ans!=-1) ans=mp[ans];
		printf("%d\n",ans);
	}
}
posted @ 2017-03-26 19:09  Candy?  阅读(476)  评论(0编辑  收藏  举报