Bzoj3545:[ONTAK2010]Peaks:Splay启发式合并

题目链接:[ONTAK2010]Peaks

离线,将边按照边权从小到大排序,询问按照x从小到大排序

对于每个询问,将边权小于他的x的边加入图中,用splay维护每个联通块的权值,查找第k大即可

加入一条边时会合并联通块,这个用Splay的启发式合并

#include
#include
#include
#include
using namespace std;
const int maxn=500010;
int n,m,f[maxn],Q,qu[maxn],ans[maxn];
struct edge{int a,b,w;}e[maxn];
struct ques{int v,x,k,id;}q[maxn];
struct Nodes{
	int c[2],fa,v,s;
};
struct Splay_tree{
	Nodes t[maxn];
	void init(){
		for (int i=1;i<=n;++i) scanf("%d",&t[i].v),t[i].s=1,f[i]=i;
	}
	void push_up(int x){
		if (!x) return;
		t[x].s=t[t[x].c[0]].s+t[t[x].c[1]].s+1;
	}
	void rotate(int p,int x){
		int mark= p==t[x].c[1];
		int y=t[p].c[mark^1],z=t[x].fa;
		if (t[z].c[0]==x) t[z].c[0]=p;
		if (t[z].c[1]==x) t[z].c[1]=p;
		if (y) t[y].fa=x; t[x].c[mark]=y;
		t[p].fa=z; t[p].c[mark^1]=x; t[x].fa=p;
		push_up(x);
	}
	void splay(int p,int k){
		while (t[p].fa!=k){
			int x=t[p].fa,y=t[x].fa;
			if (y==k) rotate(p,x);
			else if (p==t[x].c[0]^x==t[y].c[0]) rotate(p,x),rotate(p,y);
			else rotate(x,y),rotate(p,x);
		}push_up(p);
	}
	void ins(int &x,int anc,int now){
		if (!x){
			x=now; t[x].fa=anc;
			t[x].s=1; splay(x,0);
			return;
		}
		if (t[now].v<=t[x].v) ins(t[x].c[0],x,now);
		else ins(t[x].c[1],x,now);
		push_up(x);
	}
	void merge(int x,int y){
		splay(x,0); splay(y,0);
		if (t[x].s>t[y].s) swap(x,y);
		int head=0,tail=1; qu[0]=y; qu[1]=x;
		while (head=k) return qkth(t[x].c[1],k);
		else if (t[t[x].c[1]].s+1==k) return t[x].v;
		else return qkth(t[x].c[0],k-t[t[x].c[1]].s-1);
	}
	void debug(int x){
		if (t[x].c[0]) debug(t[x].c[0]);
		printf("%d ",t[x].v);
		if (t[x].c[1]) debug(t[x].c[1]);
	}
}s;

bool cmp(const edge &a,const edge &b){
	return a.w


你可能感兴趣的:(OI,splay)