zoukankan      html  css  js  c++  java
  • BZOJ4537 HNOI2016最小公倍数(莫队+并查集)

      考虑边只有一种权值的简化情况。那么当且仅当两点可以通过边权<=x的边连通,且连通块内最大边权为x时,两点间存在路径max为x的路径。可以发现两种权值是类似的,当且仅当两点可以通过边权1<=x且边权2<=y的边连通,且连通块内最大边权1为x、最大边权2为y时,两点间存在路径max为(x,y)的路径。

      一种权值的情况很好处理,从小到大加边并查集维护即可。观察数据范围容易想到根号算法。考虑类似回滚莫队的做法。按边权1将边分块,块内按边权2排序。处理某块时将所有权值1恰好小于该块max的询问找出来按边权2排序,依次处理,每次加入之前块中边权2不大于它的边,然后在块内暴力找满足条件的边加入,使用带撤销并查集即可维护。

      注意存在u=v,a=b=0的询问,所以集合内权值最大值的初值不能设成0。

      调了半天以为有什么细节问题,结果发现并查集整个写错了,居然luogu还有80分数据水爆了啊。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 50010
    #define M 100010
    #define inf 1000000000
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int n,m,q,t,L[N],R[N],fa[N],mx[N],mxa[N],mxb[N],ans[N],cur[N],size[N],cnt;
    int top;
    struct data
    {
        int x,y,a,b,k,i;
        bool operator <(const data&t) const
        {
            return k<t.k||k==t.k&&b<t.b;
        }
    }e[M],a[N],undo[N];
    int find(int x){return fa[x]==x?x:find(fa[x]);}
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4537.in","r",stdin);
        freopen("bzoj4537.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read();
        int block=sqrt(m);
        for (int i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].a=read(),e[i].b=read(),e[i].k=e[i].a;
        sort(e+1,e+m+1);
        for (int i=1;i<=m;i++)
        {
            e[i].k=(i-1)/block,mx[(i-1)/block]=max(mx[(i-1)/block],e[i].a),R[(i-1)/block]=max(R[(i-1)/block],i);
            if ((i-1)%block==0) L[(i-1)/block]=i;
        }
        cnt=(m-1)/block+1;mx[cnt]=inf+1;R[cnt]=-1;
        sort(e+1,e+m+1);
        q=read();
        for (int i=1;i<=q;i++)
        {
            a[i].x=read(),a[i].y=read(),a[i].a=read(),a[i].b=read(),a[i].i=i;
            for (int j=0;j<=cnt;j++) if (a[i].a<mx[j]) {a[i].k=j;break;}
        }
        sort(a+1,a+q+1);
        int x=0;
        for (int i=0;i<=cnt;i++)
        {
            for (int i=1;i<=n;i++) fa[i]=i,size[i]=1;
            memset(mxa,255,sizeof(mxa));
            memset(mxb,255,sizeof(mxb));
            for (int j=0;j<i;j++) cur[j]=L[j]-1;
            while (x<q&&a[x+1].k==i)
            {
                x++;
                for (int j=0;j<i;j++)
                while (e[cur[j]+1].k==j&&e[cur[j]+1].b<=a[x].b) 
                {
                    cur[j]++;
                    int p=find(e[cur[j]].x),q=find(e[cur[j]].y);
                    if (size[p]<size[q]) swap(p,q);
                    if (p!=q) size[p]+=size[q];
                    fa[q]=p;mxa[p]=max(max(mxa[p],mxa[q]),e[cur[j]].a),mxb[p]=max(max(mxb[p],mxb[q]),e[cur[j]].b);
                }
                int top=0;
                for (int j=L[i];j<=R[i];j++)
                {
                    if (e[j].b>a[x].b) break;
                    if (e[j].a<=a[x].a)
                    {
                        int p=find(e[j].x),q=find(e[j].y);
                        if (size[p]<size[q]) swap(p,q),swap(e[j].x,e[j].y);
                        top++;undo[top].x=q,undo[top].i=size[p];
                        undo[top].y=p,undo[top].a=mxa[p],undo[top].b=mxb[p];
                        if (p!=q) size[p]+=size[q];
                        fa[q]=p;mxa[p]=max(max(mxa[p],mxa[q]),e[j].a),mxb[p]=max(max(mxb[p],mxb[q]),e[j].b);
                    }
                }
                if (find(a[x].x)==find(a[x].y)&&mxa[find(a[x].x)]==a[x].a&&mxb[find(a[x].x)]==a[x].b) ans[a[x].i]=1;
                for (;top;top--)
                {
                    mxa[undo[top].y]=undo[top].a,mxb[undo[top].y]=undo[top].b;
                    fa[undo[top].x]=undo[top].x;size[undo[top].y]=undo[top].i;
                }
            }
        }
        for (int i=1;i<=q;i++) printf(ans[i]?"Yes
    ":"No
    ");
        return 0;
    }
  • 相关阅读:
    ural1238. Folding(记忆化)
    URAL1410. Crack
    树套树Day1线段树套平衡树bzoj3196
    noipd2t3列队
    NOIP2017D1T3
    uoj279温暖会指引我们前行
    一篇打脸文
    Link-Cut Tree
    重口味费用流
    bzoj1000~1025
  • 原文地址:https://www.cnblogs.com/Gloid/p/9896376.html
Copyright © 2011-2022 走看看