zoukankan      html  css  js  c++  java
  • 题解 Luogu P4197 Peaks

    题意

    给定 (n) 个点 (m) 条边的无向图,点有点权,边有边权。具体来说,第 (i) 个点的点权是 (h_i),第 (i) 条边 ((a_i,b_i)) 的边权为 (c_i)(q) 次询问,每次询问从某个点出发只经过边权小于等于 (x) 的边能到达的点中权值第 (k) 的点的权值。

    (1 leq n leq 10^5, 0leq m,q leq 5 imes 10^5, 0 leq h_i,c_i,x leq 10^9)

    题解

    考虑离线,把 (x) 排序,这样就变成了只有加边操作。

    加边操作就是合并两个连通块。平衡树启发式合并?(log^2),慢走不送。

    当然是线段树合并啦。这样可以做到 (O(n log n + q log n)) 的优秀复杂度。

    # include <bits/stdc++.h>
    
    const int N=100010,M=500010,INF=0x3f3f3f3f;
    
    struct Node{
    	int lc,rc,sum;
    }tree[N*50];
    int cnt;
    struct Edge{
    	int u,v,w;
    	bool operator < (const Edge &rhs) const{
    		return w<rhs.w;
    	}
    }edge[M];
    struct Queries{
    	int v,x,k,id;
    	bool operator < (const Queries &rhs) const{
    		return x<rhs.x;
    	}
    }a[M];
    int n,m,q;
    int h[N];
    int b[N],bcnt;
    int f[N],root[N];
    int ans[M];
    inline int read(void){
    	int res,f=1;
    	char c;
    	while((c=getchar())<'0'||c>'9')
    		if(c=='-')f=-1;
    	res=c-48;
    	while((c=getchar())>='0'&&c<='9')
    		res=res*10+c-48;
    	return res*f;
    }
    inline int find(int x){
    	return (f[x]==x)?x:(f[x]=find(f[x]));
    }
    inline int& lc(int x){
    	return tree[x].lc;
    }
    inline int& rc(int x){
    	return tree[x].rc;
    } 
    void change(int &k,int l,int r,int x){
    	k=(k?k:++cnt);
    	++tree[k].sum;
    	if(l==r)
    		return;
    	int mid=(l+r)>>1;
    	if(x<=mid)
    		change(lc(k),l,mid,x);
    	else
    		change(rc(k),mid+1,r,x);
    	return;
    }
    int query(int now,int l,int r,int k){
    	if(l==r){
    		return l;
    	}
    	int mid=(l+r)>>1;
    	if(k<=tree[rc(now)].sum)
    		return query(rc(now),mid+1,r,k);
    	return query(lc(now),l,mid,k-tree[rc(now)].sum);
    }
    void merge(int &now,int pL,int pR,int l,int r){
    	if(!pL||!pR){
    		now=pL|pR;
    		return;
    	}
    	now=pL;	
    	if(l==r){
    		tree[now].sum=tree[pL].sum+tree[pR].sum;
    		return;
    	}
    	int mid=(l+r)>>1;
    	merge(lc(now),lc(pL),lc(pR),l,mid),merge(rc(now),rc(pL),rc(pR),mid+1,r);
    	tree[now].sum=tree[lc(now)].sum+tree[rc(now)].sum;
    	return;
    }
    int main(void){
    	n=bcnt=read(),m=read(),q=read();
    	for(int i=1;i<=n;++i){
    		h[i]=b[i]=read();
    	}
    	for(int i=1;i<=m;++i){
    		edge[i].u=read(),edge[i].v=read(),edge[i].w=read();
    	}
    	for(int i=1;i<=q;++i){
    		a[i].id=i,a[i].v=read(),a[i].x=read(),a[i].k=read(); 
    	}
    	std::sort(edge+1,edge+1+m),std::sort(a+1,a+1+q);
    	std::sort(b+1,b+1+bcnt),bcnt=std::unique(b+1,b+1+bcnt)-(b+1);
    	for(int i=1;i<=n;++i){
    		h[i]=std::lower_bound(b+1,b+1+bcnt,h[i])-b;
    		f[i]=i,change(root[i],1,bcnt,h[i]);
    	}
    	int pt=1; 
    	for(int i=1;i<=q;++i){
    		while(pt<=m&&edge[pt].w<=a[i].x){
    			int u=find(edge[pt].u),v=find(edge[pt].v);
    			if(u==v){
    				++pt;
    				continue;
    			}
    			f[u]=v;
    			merge(root[v],root[u],root[v],1,bcnt);
    			++pt;
    		}
    		int nrt=root[find(a[i].v)];
    		if(tree[nrt].sum<a[i].k){
    			ans[a[i].id]=-1;
    		}else{
    			ans[a[i].id]=b[query(nrt,1,bcnt,a[i].k)];
    		}
    	}
    	for(int i=1;i<=q;++i){
    		printf("%d
    ",ans[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    hdu 2795 Billboard
    serialusbfn.dll这个罪魁祸首搞得我郁闷之极(作者:wogoyixikexie@gliet)
    开发板买来后如何练习写驱动、开发BSP?(作者:wogoyixikexie@gliet)
    PB命令行——查看DLL导出函数
    【劲爆】发帖达到要求即可获得一块mini6410/OK6410开发板!
    GOD!我终于找到博客园设置博客文章图片签名的方法了!
    如何删除wince5.0控制面板的密码设置以及拨号等组件
    【原创】最值得推荐wince应用和wince驱动入门书籍
    gooogleman嵌入式联盟之图标初步设计进展
    2440 5.0BSP之OEMInterruptHandler函数
  • 原文地址:https://www.cnblogs.com/liuzongxin/p/15256830.html
Copyright © 2011-2022 走看看