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;
    }
  • 相关阅读:
    前端一站式学习地址
    springboot注解开发
    java中的四种内部类使用(1)
    java内存回收机制
    TweenMax详解
    flash渲染机制
    通过字符串名访问变量
    总结调用Flash的几种方法
    flex buider2 的注册
    转:FlexChn.Cn Adobe Flex最佳学习路线
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793416.html
Copyright © 2011-2022 走看看