View on GitHub

Wenchong Huang

旧博客,文章搬迁完后删除

返回首页

【BZOJ3545】【ONTAK2010】Peaks 题解

闲谈

·这道题是BZOJ上的权限题,没办法发链接,反正我是在广州二中的OJ上做的

·然后广州二中的OJ特别恶心,卡常能力惊人,再加上yww大佬的疯狂hack,导致数据异常强大

·所以要用尽各种奇技淫巧进行鬼畜优化

·不过我都还没用读入优化,居然还是A了

题解

·还是权值线段树的合并

·这题比较好的是它不强制在线,因此我们可以考虑离线做法

·把边按边权从小到大排序,询问按x从小到大排序,这样我们就可以顺次加边

·每处理一个询问时,把边权比该组询问的x小的边给加上就行

·反正路径都是双向的,因此跟图论就一点关系都没有了,只要用并查集维护联通关系就好了

·初始时,我们对每个点建立一棵权值线段树,动态开点,否则MLE

·然后每次连边,我们先用并查集找到“祖父”,然后如果它们原来是联通的,就不管它,否则就将两颗权值线段树合并

·询问只要对相应的权值线段树进行kth操作就行了,注意题目要求第k大,而不是第k小

·这样会TLE最后一个点

·因此我们进行一步重要的优化——离散化

·把题目中的h数组离散化,这样权值线段树的规模就大大缩小了,数量级从10^9缩减到了10^5

·细节参考代码

#include<bits/stdc++.h>
#define newnode(x) x=new Node,x->ls=x->rs=null
#define MAXN 100000
#define MAXM 500000
using namespace std;

struct Node
{
	Node *ls,*rs;
	int sum;
	Node(){ls=rs=NULL;sum=0;}
};
Node *root[MAXN+10],*null;
struct Edge{int from,to,capa;} t[MAXM+10];
struct Query{int u,x,k,id;} Q[MAXM+10];
int fa[MAXN+10];
int ans[MAXM+10];
int Hash[MAXN+10];
int val[MAXN+10];

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

bool cmpE(const Edge &x,const Edge &y){return x.capa<y.capa;}
bool cmpQ(const Query &x,const Query &y){return x.x<y.x;}

void maintain(Node *o){o->sum=o->ls->sum+o->rs->sum;}

void insert(Node* &o,int l,int r,int x)
{
	newnode(o);
	o->sum=1;
	if(l==r) return;
	int mid=(l+r)/2;
	if(x<=mid) insert(o->ls,l,mid,x);
	else insert(o->rs,mid+1,r,x);
}

Node *merge(Node *p1,Node *p2)
{
	if(p1==null) return p2;
	if(p2==null) return p1;
	if(p1->ls==null&&p1->rs==null)
	{
		p1->sum=p1->sum+p2->sum;
		return p1;
	}
	p1->ls=merge(p1->ls,p2->ls);
	p1->rs=merge(p1->rs,p2->rs);
	maintain(p1);
	return p1;
}

int kth(Node *o,int l,int r,int x)
{
	if(l==r) return l;
	int size=o->ls->sum;
	int mid=(l+r)/2;
	if(x<=size) return kth(o->ls,l,mid,x);
	else return kth(o->rs,mid+1,r,x-size);
}

int main()
{
	null=new Node;
	null->ls=null->rs=null;
	int n,m,q,u,x,k;
	cin>>n>>m>>q;
	for(int i=1;i<=n;i++) scanf("%d",val+i),Hash[i]=val[i];
	for(int i=1;i<=m;i++) scanf("%d%d%d",&t[i].from,&t[i].to,&t[i].capa);
	for(int i=1;i<=q;i++) scanf("%d%d%d",&Q[i].u,&Q[i].x,&Q[i].k),Q[i].id=i;
	sort(Hash+1,Hash+1+n);
	int hs=unique(Hash+1,Hash+1+n)-(Hash+1);
	for(int i=1;i<=n;i++)
	{
		val[i]=lower_bound(Hash+1,Hash+1+hs,val[i])-Hash;
		insert(root[i],1,hs,val[i]);
	}
	sort(t+1,t+1+m,cmpE);
	sort(Q+1,Q+1+q,cmpQ);
	int pos=1;
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=q;i++)
	{
		u=Q[i].u;x=Q[i].x;k=Q[i].k;
		while(pos<=m&&t[pos].capa<=x)
		{
			int fr=t[pos].from,to=t[pos].to,cap=t[pos].capa;
			pos++;
			int ffr=find(fr),fto=find(to);
			if(ffr==fto) continue;
			fa[ffr]=fto;
			root[fto]=merge(root[ffr],root[fto]);
		}
		int fu=find(u);
		if(root[fu]->sum<k) ans[Q[i].id]=-1;
		else ans[Q[i].id]=Hash[kth(root[fu],1,hs,root[fu]->sum-k+1)];
	}
	for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
	return 0;
}