zoukankan      html  css  js  c++  java
  • 【BZOJ3551】[ONTAK2010]Peaks加强版 最小生成树+DFS序+主席树

    【BZOJ3545】[ONTAK2010]Peaks

    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。

    【BZOJ3551】[ONTAK2010]Peaks加强版

    题意:同3545,强制在线

    题解:3545:这道题我们很容易想到用最小生成树,然后离线来搞。将询问按照x排序,在最小生成树加边的过程中,每加一条边就把所有x小于当前边权的询问处理掉。求第k大可以用Treap搞定,将并查集合并时也将Treap进行启发式合并(把小的Treap暴力拆掉,一个一个加到大的中去),不过我有点懒得写了。

    3551:既然是强制在线我们就不能用Treap搞了,但最小生成树是一定要求的。本题利用到了Kruskal重构树的性质(什么是Kurskal重构树?)

    在并查集合并的时候,我们不直接令f[a]=b,而是新建一个点ext,将a和b都合并到以ext为根的并查集上,并且令ext的点权等于e(a,b)的边权,这样我们就得到了一棵Kruskal重构树,本题的Kruskal重构树如下图所示

    容易发现,Kruskal重构树满足:子节点的边权一定小于父亲节点的边权。于是我们可以用倍增求出v的深度最小的、且满足边权不超过x的祖先,因此满足所有到v路径上最大边权不超过x的节点,一定就在这棵子树上,然后询问就变成了求这棵子树中的第k大。为此我们只需要用DFS序,然后就可以将求子树的第k大转变成求一段区间中的第k大,这样跑一遍主席树就行了。

    再捋一下思路:先离散化(因为是10^9),在跑Kruskal,顺便建树,然后预处理倍增,求出DFS序,再预处理主席树,最后在线处理询问

    由于本人比较懒我就直接用3551的代码改一改就把3545交了,但其实写一发Treap也是挺好的

    至于TLE的建议写个读入优化吧,没准就AC了。

    3551代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn=200010;
    int n,m,Q,cnt,tot,sum,H,ans;
    struct edge
    {
        int pa,pb,len;
    }p[500010];
    struct node
    {
        int siz,ls,rs;
    }s[4000000];
    struct NUM
    {
        int num,org;
    }v[maxn];
    int h[maxn],f[maxn],bel[maxn],fa[maxn][20],dp[maxn][20],Log[maxn],to[maxn],next[maxn],root[maxn];
    int qx[maxn],qy[maxn],qz[maxn],ql[maxn],qr[maxn],q[maxn],rx[maxn],rh[maxn],head[maxn];
    bool cmp1(edge a,edge b)
    {
        return a.len<b.len;
    }
    bool cmp2(NUM a,NUM b)
    {
        return a.num<b.num;
    }
    int readin()
    {
        int ret=0,f=1;    char gc=getchar();
        while(gc<'0'||gc>'9'){if(gc=='-')f=-f;    gc=getchar();}
        while(gc>='0'&&gc<='9')    ret=ret*10+gc-'0',gc=getchar();
        return ret*f;
    }
    int find(int x)
    {
        if(f[x]!=x)    f[x]=find(f[x]);
        return f[x];
    }
    void add(int a,int b)
    {
        if(b==0)    return ;
        to[cnt]=b;
        next[cnt]=head[a];
        head[a]=cnt++;
    }
    void dfs(int x)
    {
        ql[x]=q[0];
        if(head[x]==-1)    q[++q[0]]=x;
        for(int i=head[x];i!=-1;i=next[i])    dfs(to[i]);
        qr[x]=q[0];
    }
    void RMQ()
    {
        int i,j;
        for(i=2;i<=2*n;i++)    Log[i]=Log[i>>1]+1;
        for(j=1;(1<<j)<=2*n;j++)
            for(i=1;i+(1<<j)-1<=2*n;i++)
                fa[i][j]=fa[fa[i][j-1]][j-1];
    }
    void insert(int x,int &y,int l,int r,int pos)
    {
        y=++tot;
        if(l==r)
        {
            s[y].siz=s[x].siz+1;
            return ;
        }
        int mid=l+r>>1;
        if(pos<=mid)    s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,pos);
        else    s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,pos);
        s[y].siz=s[s[y].ls].siz+s[s[y].rs].siz;
    }
    void query(int x,int y,int l,int r,int pos)
    {
        if(l==r)
        {
            ans=rh[l];
            return ;
        }
        int mid=l+r>>1;
        if(s[s[y].rs].siz-s[s[x].rs].siz>=pos)    return query(s[x].rs,s[y].rs,mid+1,r,pos);
        return query(s[x].ls,s[y].ls,l,mid,pos-s[s[y].rs].siz+s[s[x].rs].siz);
    }
    int main()
    {
        n=readin(),m=readin(),Q=readin();
        memset(head,-1,sizeof(head));
        int i,j,a,b,c;
        for(i=1;i<=n;i++)    v[i].num=readin(),v[i].org=i;
        sort(v+1,v+n+1,cmp2);
        rh[H]=-1;
        for(i=1;i<=n;i++)
        {
            if(rh[H]<v[i].num)    rh[++H]=v[i].num;
            h[v[i].org]=H;
        }
        for(i=1;i<=m;i++)    p[i].pa=readin(),p[i].pb=readin(),p[i].len=readin();
        sort(p+1,p+m+1,cmp1);
        for(i=1;i<2*n;i++)    f[i]=i;
        for(i=1;i<=m;i++)
        {
            a=find(p[i].pa),b=find(p[i].pb);
            if(a!=b)
            {
                sum++;
                add(sum+n,a),add(sum+n,b);
                f[a]=f[b]=sum+n;
                fa[a][0]=fa[b][0]=sum+n;
                rx[sum]=p[i].len;
                if(sum==n-1)    break;
            }
        }
        dfs(sum+n);
        for(i=1;i<=n;i++)    insert(root[i-1],root[i],1,H,h[q[i]]);
        RMQ();
        for(i=1;i<=Q;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            a^=ans,b^=ans,c^=ans;
            int temp=a;
            for(j=Log[2*n];j>=0;j--)
                if(fa[temp][j]&&rx[fa[temp][j]-n]<=b)
                    temp=fa[temp][j];
            if(c>qr[temp]-ql[temp])
            {
                printf("-1
    ");
                ans=0;
                continue;
            }
            query(root[ql[temp]],root[qr[temp]],1,H,c);
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    cf1100 F. Ivan and Burgers
    cf 1033 D. Divisors
    LeetCode 17. 电话号码的字母组合
    LeetCode 491. 递增的子序列
    LeetCode 459.重复的子字符串
    LeetCode 504. 七进制数
    LeetCode 3.无重复字符的最长子串
    LeetCode 16.06. 最小差
    LeetCode 77. 组合
    LeetCode 611. 有效三角形个数
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6293572.html
Copyright © 2011-2022 走看看