• bzoj 3545/3551: [ONTAK2010]Peaks -- 主席树,最小生成树,倍增


    3545: [ONTAK2010]Peaks

    Time Limit: 10 Sec  Memory Limit: 128 MB

    Description

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

    Input

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

    Output

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

    Sample Input

    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

    Sample Output

    6
    1
    -1
    8


    HINT

    【数据范围】

    N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。

    Source

    首先一定是走最小生成树上的边是最优的,然后我们按建树的顺序合并节点,这样我们发现一个子树里的边权都小于他本身

    然后查询就是倍增找到当前点能到的最远的祖先,就变成了查询子树的第k大,然后用主席树维护就可以了

    #include<map>
    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define inf 1000000007
    #define ll long long
    #define M 6000010
    #define N 500010
    inline int rd()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,m,Q;
    int h[N];
    struct qaz{int a,b,c;}e[N],tp[N];
    bool cmp(qaz a,qaz b){return a.c<b.c;}
    int fa[N],mz;
    int findf(int x){return x==fa[x]?x:fa[x]=findf(fa[x]);}
    int lj[N],fro[N],to[N],cnt;
    void add(int a,int b){fro[++cnt]=lj[a];to[cnt]=b;lj[a]=cnt;}
    bool vs[N];
    int st[N],ed[N],tim,dep[N];
    int Fa[200010][17],rt[N];
    int ls[M],rs[M],sz[M],tot;
    void add(int lst,int &p,int l,int r,int x)
    {
        p=++tot;
        ls[p]=ls[lst];rs[p]=rs[lst];
        sz[p]=sz[lst]+1;
        if(l==r) return;
        int mid=l+r>>1;
        if(x<=mid) add(ls[lst],ls[p],l,mid,x);
        else add(rs[lst],rs[p],mid+1,r,x);
    }
    void dfs(int x)
    {
        st[x]=++tim;vs[x]=1;
        dep[x]=dep[Fa[x][0]]+1;
        if(x<=n) add(rt[tim-1],rt[tim],1,n,h[x]);
        else rt[tim]=rt[tim-1];
        for(int i=1;i<17;i++)
        {
            if(dep[x]<(1<<i)) break;
            Fa[x][i]=Fa[Fa[x][i-1]][i-1];
        }
        for(int i=lj[x];i;i=fro[i])
        {
            Fa[to[i]][0]=x;
            dfs(to[i]);
        }
        ed[x]=tim;
    }
    int fd(int x,int y,int l,int r,int k)
    {
        if(l==r) return tp[l].c;
        int mid=l+r>>1;
        if(sz[rs[x]]-sz[rs[y]]>=k) return fd(rs[x],rs[y],mid+1,r,k);
        else return fd(ls[x],ls[y],l,mid,k-sz[rs[x]]+sz[rs[y]]);
    }
    int main()
    {
        mz=n=rd();m=rd();Q=rd();
        for(int i=1;i<=n;i++) tp[i].c=rd(),tp[i].a=i;
        sort(tp+1,tp+n+1,cmp);
        for(int i=1;i<=n;i++)
        {
            if(i>1&&tp[i].c==tp[i-1].c) h[tp[i].a]=h[tp[i-1].a];
            else h[tp[i].a]=i;
        }
        for(int i=1,a,b,c;i<=m;i++)
        {
            a=rd();b=rd();c=rd();
            e[i]=(qaz){a,b,c}; 
        }
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<n+n;i++) fa[i]=i;
        for(int i=1,x,y;i<=m;i++)
        {
            x=findf(e[i].a);y=findf(e[i].b);
            if(x==y) continue;
            fa[x]=fa[y]=++mz;
            h[mz]=e[i].c;
            add(mz,x);add(mz,y);
            if(mz==n*2-1) break;
        }
        for(int i=1;i<=n;i++) if(!vs[i]) dfs(findf(i));
        int x,y,z,lans=-1,Rt;
        while(Q--)
        {
            x=rd();y=rd();z=rd();
            Rt=x;
            for(int i=16;i>=0;i--)
                if(dep[Rt]>(1<<i)&&h[Fa[Rt][i]]<=y)  Rt=Fa[Rt][i];
            if(sz[rt[ed[Rt]]]-sz[rt[st[Rt]-1]]<z) lans=-1;
            else lans=fd(rt[ed[Rt]],rt[st[Rt]-1],1,n,z);
            printf("%d
    ",lans);
        }
        return 0;
    }
  • 相关阅读:
    mysql学习总结(四)
    mysql学习总结(三)
    mysql学习总结(二)
    mysql学习总结
    学习总结(三十)
    断点续传
    错误总结
    学习总结(三十六)
    学习总结(三十五)
    Linux命令
  • 原文地址:https://www.cnblogs.com/lkhll/p/7845118.html
Copyright © 2020-2023  润新知