zoukankan      html  css  js  c++  java
  • 【BZOJ4537】最小公倍数(HNOI2016)-分块+并查集启发式合并

    测试地址:最小公倍数
    做法:本题需要用到分块+并查集启发式合并。
    脱去题目各种疑似数论的包装之后,我们发现实际上题目让你求的是:存不存在一条路径,使得路径上最大的a和最大的b分别为询问的AB。显然如果只有一个询问的话,我们就把aA并且bB的边连起来,再用并查集维护联通块内最大的a和最大的b,如果询问的两个点连通并且最大的ab分别等于AB,那就存在这样一条路径,否则就不存在。那么现在的问题是怎么把aA,bB的这些边取出来。
    考虑两种暴力:
    1.每次扫一遍所有的边,将所有aA,bB的边连起来,用并查集维护。
    2.将边按a排序,将询问按B排序,每次处理一个询问时,将aA的边按b从小到大排序,处理对应的边。
    我们将这两种暴力折中起来,成为一个分块算法,具体如下:
    将边按a排序,将询问按B排序,然后将边分块,对于每一块,处理A在这一块内的询问,做法就是:对于前面所有块中的边,因为在前面的块中a必然A,那么这些边只要在询问的B到某个程度的时候是一定会被加入的,所以我们把这些边按b排序,这样就能保证前面块中的边在处理每一块时只会处理一次。对于块内的边,暴力扫一遍将符合条件的边全部处理。注意在处理一个新的询问之前,我们还要将一些操作撤销,所以并查集不能路径压缩,那么就必须使用启发式合并来保证时间复杂度,那么我们就得到了一个复杂度为O(mmlogn)的算法。实践证明(实际上是抄的题解),块大小为mlogn时是最优的。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,q,blocksiz,changed[50010],s[50010];
    bool vis[50010]={0},ans[50010]={0};
    struct node
    {
        int fa,mxa,mxb,h;
    }a[50010],ori[50010];
    struct edge
    {
        int u,v,a,b,id;
    }e[100010],Q[50010];
    
    void init()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
            scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].a,&e[i].b);
        scanf("%d",&q);
        for(int i=1;i<=q;i++)
        {
            scanf("%d%d%d%d",&Q[i].u,&Q[i].v,&Q[i].a,&Q[i].b);
            Q[i].id=i;
        }
    }
    
    bool cmp(edge a,edge b)
    {
        if (a.a!=b.a) return a.a<b.a;
        else return a.b<b.b;
    }
    
    bool cmpb(edge a,edge b)
    {
        return a.b<b.b;
    }
    
    int find(int x)
    {
        while(x!=a[x].fa) x=a[x].fa;
        return x;
    }
    
    void change(int x)
    {
        vis[x]=1;
        changed[++changed[0]]=x;
        ori[x]=a[x];
    }
    
    void merge(int x,int y,int i,bool type)
    {
        int fx=find(x),fy=find(y);
        if (a[fx].h>a[fy].h) swap(fx,fy);
        if (type&&!vis[fx]) change(fx);
        if (type&&!vis[fy]) change(fy);
        if (fx==fy)
        {
            a[fx].mxa=max(a[fx].mxa,e[i].a);
            a[fx].mxb=max(a[fx].mxb,e[i].b);
            return;
        }
        a[fx].fa=fy;
        a[fy].mxa=max(max(a[fx].mxa,a[fy].mxa),e[i].a);
        a[fy].mxb=max(max(a[fx].mxb,a[fy].mxb),e[i].b);
        a[fy].h=max(a[fy].h,a[fx].h+1);
    }
    
    void work()
    {
        blocksiz=sqrt(m);
        sort(e+1,e+m+1,cmp);
        sort(Q+1,Q+q+1,cmpb);
    
        int top;
        for(int i=1;i<=m;i+=blocksiz)
        {
            for(int j=1;j<=n;j++)
            {
                a[j].fa=j;
                a[j].mxa=a[j].mxb=-1;
                a[j].h=1;
            }
            sort(e+1,e+i,cmpb);
    
            top=0;
            for(int j=1;j<=q;j++)
                if (Q[j].a>=e[i].a&&(i+blocksiz>m||Q[j].a<e[i+blocksiz].a))
                    s[++top]=j;
    
            int nowp=1;
            for(int k=1;k<=top;k++)
            {
                int nowq=s[k];
                while(nowp<i&&e[nowp].b<=Q[nowq].b)
                {
                    merge(e[nowp].u,e[nowp].v,nowp,0);
                    nowp++;
                }
                changed[0]=0;
                for(int j=i;j<=min(i+blocksiz-1,m);j++)
                    if (e[j].a<=Q[nowq].a&&e[j].b<=Q[nowq].b)
                        merge(e[j].u,e[j].v,j,1);
    
                int fx=find(Q[nowq].u),fy=find(Q[nowq].v);
                ans[Q[nowq].id]=(fx==fy&&a[fx].mxa==Q[nowq].a&&a[fx].mxb==Q[nowq].b);
    
                for(int j=1;j<=changed[0];j++)
                {
                    a[changed[j]]=ori[changed[j]];
                    vis[changed[j]]=0;
                }
            }
        }
    }
    
    void output()
    {
        for(int i=1;i<=q;i++)
        {
            if (ans[i]) printf("Yes
    ");
            else printf("No
    ");
        }
    }
    
    int main()
    {
        init();
        work();
        output();
    
        return 0;
    }
  • 相关阅读:
    《DSP using MATLAB》Problem 6.17
    一些老物件
    《DSP using MATLAB》Problem 6.16
    《DSP using MATLAB》Problem 6.15
    《DSP using MATLAB》Problem 6.14
    《DSP using MATLAB》Problem 6.13
    《DSP using MATLAB》Problem 6.12
    《DSP using MATLAB》Problem 6.11
    P1414 又是毕业季II
    Trie树
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793416.html
Copyright © 2011-2022 走看看