【BZOJ】【P3545】【ONTAK2010】【Peaks】【题解】【离线+并查集+平衡树启发式合并】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3545

离线做法显然,并查集显然,Treap显然,启发式合并显然……加强版不会做唉……

Code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int maxm=5e5+10;
int n,m,q;
int getint(){
	int res=0;char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))res=(res<<3)+(res<<1)+ch-'0',ch=getchar();
	return res;
}
int rnd(){
	static int KEY=12345678;
	return KEY+=KEY<<2|1;
}
struct node{
	int val,key,size,s;
	node *c[2];
    void rz(){  
        size=c[0]->size+s+c[1]->size;  
    }  
    void set(int _val=0,int _key=rnd(),int _size=1,int _s=1,node *C=NULL){  
        val=_val;key=_key;size=_size;s=_s;c[0]=c[1]=C;  
    }  
};
node pool[maxn];
node* newnode(){
	static int tot=0;
	if(tot<maxn)return &pool[tot++];
	return new node();
}
struct Treap{
	node *root,*Null;
	Treap(){
		Null=newnode();
		Null->set(0,INT_MAX,0,0,Null);
		root=Null;
	}	
   void rot(node *&t,bool d){  
        node *p=t->c[d];t->c[d]=p->c[!d];  
        p->c[!d]=t;t->rz();p->rz();t=p;  
    }  
    void _insert(node *&t,int x){  
        if(t==Null){t=newnode();t->set(x,rnd(),1,1,Null);return;}  
        if(t->val==x){t->size+=1;t->s+=1;return;}  
        _insert(t->c[x>t->val],x);  
        if(t->c[x>t->val]->key<t->key)rot(t,x>t->val);  
        else t->rz();  
    }  
	int _kth(node *t,int x){
        int r=t->c[0]->size;  
        if(t==Null)return 0;  
        else if(x<=r)return _kth(t->c[0],x);  
        else if(x>r+t->s)return _kth(t->c[1],x-r-t->s);  
        else return t->val;  
	}
	void insert(int x){_insert(root,x);}
	int kth(int x){return _kth(root,x);}
	int size(){return root->size;}
}T[maxn];
int fa[maxn];
int find(int x){
	if(fa[x]!=x)return fa[x]=find(fa[x]);return x;
}
void Union(int x,int y){
	int fax=find(x),fay=find(y);
	if(fax==fay)return;
	if(T[fax].size()<T[fay].size())swap(x,y),swap(fax,fay);
	fa[fay]=fax;
	for(int i=0;i<T[fay].size();i++){
		int val=T[fay].kth(i+1);
		T[fax].insert(val);
	}
}
struct edge{
	int u,v,w;
	bool operator<(const edge &E)const{return w<E.w;}
};
edge edges[maxm];
struct qes{
	int u,x,k,ind;
	bool operator<(const qes &q)const{return x<q.x;}
};
qes Q[maxm];
int anss[maxm];
int main(){
	n=getint();m=getint();q=getint();
	for(int i=1;i<=n;i++){
		int x=getint();
		T[i].insert(x);fa[i]=i;
	}for(int i=1;i<=m;i++){
		edges[i].u=getint();
		edges[i].v=getint();
		edges[i].w=getint();
	}sort(edges+1,edges+1+m);
	for(int i=1;i<=q;i++){
		Q[i].u=getint();Q[i].x=getint();
		Q[i].k=getint();Q[i].ind=i;
	}sort(Q+1,Q+1+q);
	int now=1;
	for(int i=1;i<=q;i++){	
		for(;now<=m&&edges[now].w<=Q[i].x;now++)
		Union(edges[now].u,edges[now].v);
		int f=find(Q[i].u);
		Q[i].k=T[f].size()-Q[i].k;
		if(Q[i].k<0)anss[Q[i].ind]=-1;
		else anss[Q[i].ind]=T[f].kth(Q[i].k+1);
	}
	for(int i=1;i<=q;i++)
	printf("%d\n",anss[i]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值