zoukankan      html  css  js  c++  java
  • P4197 Peaks

    题目描述

    在Bytemountains有N座山峰,每座山峰有他的高度(h_i)。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。

    输入输出格式

    输入格式:

    第一行三个数N,M,Q。 第二行N个数,第ii个数为(h_i) 接下来MM行,每行33个数a,b,c,表示从a到b有一条困难值为c的双向路径。 接下来Q行,每行三个数v,x,k,表示一组询问。

    输出格式:

    对于每组询问,输出一个整数表示答案。

    输入输出样例

    输入样例#1: 复制

    10 11 4
    1 2 3 4 5 6 7 8 9 10
    1 4 4
    2 5 3
    9 8 2
    7 8 10
    7 1 4
    6 7 1
    6 4 8
    2 1 5
    10 8 10
    3 4 7
    3 4 6
    1 5 2
    1 5 6
    1 5 8
    8 9 2

    输出样例#1: 复制

    6
    1
    -1
    8

    说明

    数据范围

    (N le 10^5, 0 le M,Q le 5 imes 10^5,h_i,c,x le 10^9)


    kruskal重构树
    对于每一个节点其子树的叶子就是在这个点的权值内能相互到达的点
    按照dfs序建可持久化权值线段树,dfs序(u)(u+size[u])内每个点的增量就是(pre[u])子树的点
    每次查询时把(v)倍增跳到(leq x)的最大值,在((dfn[x]+size[x])-(dfn[x]-1))的线段树内找第(k)大节点即可


    恩......
    enter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description hereenter image description here


    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define M (200005*10)
    #define N 200005
    #define LL long long
    #define max(a,b) ((a)>(b)? (a):(b))
    #define min(a,b) ((a)<(b)? (a):(b))
    
    using namespace std;
    
    int top[N],d[M],h[N],ls[M],rs[M],n,m,q,cnt,f[N],edge[N],cnt1,y;
    int head[N],ver[N],nex[N],dfn[N],df,pre[M],g,z[N],pp[N],v,x,k,bz[N][26],s[N],az[N][26];
    struct vv{	int f,t,edge;} a[M];
    inline bool cmp(vv a,vv b) {return a.edge<b.edge;}
    
    inline char gc()
    {
        static char now[1<<22],*S,*T;
        if (T==S)
        {
            T=(S=now)+fread(now,1,1<<22,stdin);
            if (T==S) return EOF;
        }
        return *S++;
    }
    inline int gtt()
    {
        register int x=0,f=1;
        register char ch=gc();
        while(!isdigit(ch))
        {
            if (ch=='-') f=-1;
            ch=gc();
        }
        while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=gc();
        return x*f;
    }
    inline void add(int x,int y)
    {
    	cnt1+=1;
    	ver[cnt1]=y; nex[cnt1]=head[x]; head[x]=cnt1;
    }
    
    int ff(int x)
    {
    	if(f[x]==x) return x;
    	f[x]=ff(f[x]);
    	return f[x];
    }
    
    inline void kru()
    {
    	for(int i=1;i<=m;i++)
    	{
    		int w=ff(a[i].f), e=ff(a[i].t);
    		if(w!=e)
    		{
    			f[w]=f[e]=++n;
    			add(n,w); add(n,e);
    			edge[n]=a[i].edge;
    		}
    	}
    }
    
    void dfs(int now)
    {
    	bz[now][0]=edge[now]; 
    	s[now]=1; dfn[now]=++df; pre[df]=now;
    	for(int i=head[now];i;i=nex[i])
    	{
    		int t=ver[i];
    		dfs(t);
    		bz[t][1]=edge[now];
    		az[t][1]=now;
    		s[now]+=s[t];
    	}
    }
    
    void built(int now,int l,int r,int pre,int z)
    {
    	if(l==r)
    	{
    		d[now]=d[pre]+1;
    		return;
    	}
    	int mid=(l+r)>>1; ls[now]=ls[pre]; rs[now]=rs[pre];
    	if(z<=mid)
    	{
    		ls[now]=++cnt;
    		built(ls[now],l,mid,ls[pre],z);
    	}
    	if(z>mid)
    	{
    		rs[now]=++cnt;
    		built(rs[now], mid+1, r, rs[pre], z);
    	}
    	d[now]=d[ls[now]]+d[rs[now]];
    }
    
    void built1(int now,int l,int r)
    {
    	if(l==r) return;
    	ls[now]=++cnt; rs[now]=++cnt;
    	int mid=(l+r)>>1;
    	built1(ls[now], l, mid);
    	built1(rs[now], mid+1, r);
    }
    
    int find(int now1,int now2,int l,int r,int z)
    {
    	if(l==r) return l; 
    	if(d[now2]-d[now1]<z) return -1;
    	int mid=(l+r)>>1;
    	if(d[rs[now2]]-d[rs[now1]]>=z) return find(rs[now1], rs[now2], mid+1, r, z);
    	return find(ls[now1], ls[now2], l, mid, z-d[rs[now2]]+d[rs[now1]]);
    }
    
    int main()
    {
    	n=gtt(); m=gtt(); q=gtt();	g=n;
    	for(int i=1;i<=4*n;i++) f[i]=i;
    
    	for(int i=1;i<=n;i++) h[i]=gtt(), z[i]=h[i];
    	sort(z+1,z+1+n);
    	int mm=unique(z+1,z+1+n)-z-1;
    	for(int i=1;i<=n;i++) 
    	{
    		k=lower_bound(z+1,z+1+mm,h[i])-z;
    		pp[k]=h[i];	h[i]=k;
    	}
    	
    	for(int i=1;i<=m;i++){ a[i].f=gtt(); a[i].t=gtt(); a[i].edge=gtt();}
    	sort(a+1,a+1+m,cmp); kru(); 
    	
    	for(int i=n;i;i--)	if(!dfn[i]) dfs(i);
    	
    	if(g!=1){top[1]=1; cnt=1; built1(1,1,mm);}
    	else {top[1]=1; cnt=1;built(cnt,1,mm,0,h[pre[1]]);}
    	
    	for(int i=2;i<=n;i++) 
    		if(pre[i]<=g) 
    		{
    			top[i]=++cnt;
    			built(cnt,1,mm,top[i-1],h[pre[i]]);
    		}
    		else top[i]=top[i-1];
    	
    	for(int i=2;i<=25;i++) 
    		for(int j=1;j<=n;j++) 
    			bz[j][i]=bz[az[j][i-1]][i-1], az[j][i]=az[az[j][i-1]][i-1];
    		
    	for(int i=1;i<=q;i++)
    	{
    		v=gtt(); x=gtt(); k=gtt();
    		for(int j=25;j>=1;j--) if(bz[v][j]<=x && az[v][j]) v=az[v][j];
    		k=find(top[dfn[v]-1],top[dfn[v]+s[v]-1],1,mm,k);
    		if(k!=-1)printf("%d
    ",pp[k]);
    		else printf("-1
    ");
    		
    	}
    }
    
  • 相关阅读:
    html不点击提交,自动post
    wpf slider刻度
    visual studio 的 code snippet(代码片段)
    更换手机号之前
    post提交
    动态修改settings
    获取文件数据流+叠加byte数组(给byte数组加包头包尾)
    装箱与拆箱
    ue4中窗口打开web地址
    C++通过Callback向C#传递数据,注意问题
  • 原文地址:https://www.cnblogs.com/ZUTTER/p/9835735.html
Copyright © 2011-2022 走看看