题目链接:[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