您的位置:首页 > 其它

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

2016-07-18 15:28 405 查看
题目链接:[ONTAK2010]Peaks

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

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

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

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
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<tail){
int u=qu[++head];
if (t[u].c[0]) qu[++tail]=t[u].c[0];
if (t[u].c[1]) qu[++tail]=t[u].c[1];
t[u].c[0]=t[u].c[1]=0;
ins(qu[head-1],0,u);
}
}
int qkth(int x,int k){
if (t[x].s<k) return -1;
if (t[t[x].c[1]].s>=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<b.w;
}

bool cmp2(const ques &a,const ques &b){
return a.x<b.x;
}

int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}

int main(){
scanf("%d%d%d",&n,&m,&Q);
s.init();
for (int i=1;i<=m;++i)
scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].w);
sort(e+1,e+m+1,cmp);
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(q+1,q+Q+1,cmp2);
int pos=1;
for (int i=1;i<=Q;++i){
while (pos<=m&&e[pos].w<=q[i].x){
int a=find(e[pos].a),b=find(e[pos].b);
if (a!=b)s.merge(e[pos].a,e[pos].b),f[a]=b;
pos++;
}
int rt=find(q[i].v);
s.splay(rt,0);
ans[q[i].id]=s.qkth(rt,q[i].k);
}
for (int i=1;i<=Q;++i) printf("%d\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  BZOJ Splay 启发式合并