BZOJ 4537:[Hnoi2016]を有するブロック最小公倍数互いに素設定取消し

タイトル

BZOJ 4537

LUOGU 3247

説明

所与\(N \)の頂点を\(M \)図に縁なし(番号頂点\(1,2、...、N-\) )、各値の右側有します。値は、所有権に分解することができます\(2 ^ A * 3 ^ B \) の形。

今、そこに\(q個\)問い合わせ番目、それぞれ与えられた四つのパラメータを求めて\(Uは、V、A、B \) あなたは頂点があるかどうかを見つける\(uは\)する\(V \)の最小公倍数の重みが順次エッジの経路を通るように、間のパス\(2. 3 ^ B ^ *の\)

注:パスは、単純なパスではないかもしれません。

ここで役に立つかもしれないいくつかの定義は以下のとおりです。

最小公倍数:\(K \)番号が\(A_1、A_2、...、 a_k \) それぞれの最小公倍数であることができる(a_iを\)\最小の正の整数が割り切れます。

パス:\:(P P_1、P_2、 ...、P_k \)は任意満たさ頂点の配列である(私はK \ <1 \ leqslant)\、ノード\(P_I \)\(P_ {I + 1} \ の縁との間に接続されています。

シンプルパス:もしパス\(P:P_1、P_2、 ...、P_k \) いずれについても、\(1 \ leqslant S \ない = T \ leqslant K \) がある\(P_S \ P_T =未\) その後、彼はパスがシンプルなパスであると述べました。

入力

入力ファイルの最初の行は、2つの整数を含んでいる\(N \)\(M \)の頂点の数とグラフのエッジの数を表します。

\(M \)行、4つの整数を含む各行\(U、V、 B \) 一つの頂点を表し\(U \)\(V \)を右値間^ 2(\ * 3 ^のb \)側。

次の行は、整数含ま\(q個の\)を、問い合わせの数を表します。\(Q \)行、4つの整数を含む各行\(U、V、A、B \) クエリの代表。

依頼する問題の説明を参照してください。\(1 \ leqslant N、Q \ leqslant 50000,1 \ leqslant M \ leqslant 100000,0 \、Bの\のleqslant 10 ^ 9 \ leqslant)

出力

各問い合わせのために、パスが存在し、出力線の条件満たすためあればYes、そうでない場合は出力ラインNo(注:最初の文字が小文字を残り、大文字)。

サンプル入力

4 5
1 2 1 3
1 3 1 2
1 4 2 1
2 4 3 2
3 4 2 2
5
1 4 3 3
4 2 2 3
1 2 3 2
2 3 2 2
1 3 4 4

サンプル出力

はい
はい
はい
ません

分析

\(\)昇順に、次いでブロック。

それぞれの尋問は、取得するには、\(q_a \)によって最初に\(私は\)ブロックのすべてのエッジ\(a_e \)ブロックは、(複数の場合は、最後にAを得た)間隔で構成されています

その後に\(私は\)間隔とに応じた電流問い合わせの前に、すべての側面に係合するように(B \)\昇順インチ

次いで、エッジが存在する場合に前後から処理動作をチェックし、濃縮(接続性を維持するために、通信ブロックのそれぞれに接合\(\)\(Bの\)最大)。

尋ねられた場合は、その後、現在のブロックの法的側面内暴力(つまり、現在の二次元照会以上のものではありません)最後に、その後撤回追加したすべてのエッジを覚えておく必要性を加えることができます。

だから、互いに素-設定されたパスは、私は、馬鹿だっ設定し、結果を確認するか、簡単に、ハムをパス圧縮を書き込むためのバンド取消権を見て、圧縮できません。

ブロックサイズが問題であり、我々はブロックでも多くになりたいので、\(ソート\) そして、巨大な定数につながる可能性が...

移し、ブロックのサイズについて(\ \のSQRT {N \ログ N} \) ブラインドオペレータの複雑さ、かなり可能である\(O(N \ {N-SQRTする\ n-ログ})\) ブラインド前記なぜカウント、どこ\(nは、m個\)を(これが理由でああではないかのように)兄弟が考えるようにするとき、誰かが前に言って見ているようだ:見つかった、\(O(N-用の\ SQRT {N-ログ\ N-}) \は)あまりにも動作しない場合があります)\ \(N-ログ\ O(N-用の\ SQRT {N-を})ブロックと、結局、)私がいたとき、これは、私が(純粋なナンセンスを知らない、この問題の複雑さをサイズ関係すぎ。

コード

#include<bits/stdc++.h>

const int maxn=1e5+1e3;
typedef int iarr[maxn];

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }
}

using IO::read;

template<typename T>inline bool chkMin(T &a,const T &b) { return a>b ? (a=b, true) : false; }
template<typename T>inline bool chkMax(T &a,const T &b) { return a<b ? (a=b, true) : false; }
template<typename T>inline T min(T a,T b) { return a<b ? a : b; }
template<typename T>inline T max(T a,T b) { return a>b ? a : b; }

struct Orz
{
    int x,y,a,b,k;
    inline void Get(int k_=0)
    {
        read(x), read(y), read(a), read(b), k=k_;
    }
} E[maxn], Q[maxn], ask[maxn];

inline bool cmpa(Orz x,Orz y) { return x.a<y.a || (x.a==y.a && x.b<y.b); }
inline bool cmpb(Orz x,Orz y) { return x.b<y.b || (x.b==y.b && x.a<y.a); }

namespace Union_Set
{
    Orz Stack[maxn];
    iarr mxa,mxb,height,fa; int top;
    inline int get(int x)
    {
        return fa[x]==x ? x : get(fa[x]);//并查集不能路径压缩,否则无法撤销回去
    }

    inline Orz merge(int x,int y,int a,int b)
    {
        x=get(x), y=get(y);
        if (height[x]>height[y]) std::swap(x,y);
        Orz tmp=(Orz){x,y,mxa[y],mxb[y],height[y]};

        if (height[x]==height[y]) ++height[y];
        fa[x]=y;
        chkMax(mxa[y],max(mxa[x],a));
        chkMax(mxb[y],max(mxb[x],b));
        return tmp;
    }

    inline void del()
    {
        Orz cur=Stack[top--];
        fa[cur.x]=cur.x, mxa[cur.y]=cur.a, mxb[cur.y]=cur.b, height[cur.y]=cur.k;
    }
}

iarr Beg,End, Mina,Maxa, bel,id,ans;
int main()
{
    int n,m;read(n);read(m);
    int block=(int)(sqrt(n*log2(m)))*0.6;

    for (int i=1; i<=m; ++i) E[i].Get();
    std::sort(E+1,E+m+1,cmpa);

    for (int i=1; i<=m; ++i)
    {
        id[i]=i/block+1;
        if (id[i]!=id[i-1]) Mina[id[i]]=Maxa[id[i]]=E[i].a, Beg[id[i]]=i, End[id[i-1]]=i-1;
        else chkMin(Mina[id[i]],E[i].a), chkMax(Maxa[id[i]],E[i].a);
    }
    End[id[m]]=m;

    int q;read(q);
    for (int i=1; i<=q; ++i)
    {
        Q[i].Get(i);
        for (int j=id[m]; j>=1; --j)
            if (Mina[j]<=Q[i].a && Q[i].a<=Maxa[j]) { bel[i]=j; break; }
    }

    using namespace Union_Set;

    for (int i=1; i<=m; ++i) if (id[i]!=id[i-1])
    {
        int cnt=0;
        for (int j=1; j<=q; ++j)
            if (bel[j]==id[i]) ask[++cnt]=Q[j];
        if (!cnt) continue;

        std::sort(E+1,E+i,cmpb);
        std::sort(ask+1,ask+cnt+1,cmpb);

        for (int j=1; j<=n; ++j) fa[j]=j, mxa[j]=mxb[j]=-1;//初始化,因为 0 个数的 lcm 不是 1,所以初值为 -1
        int L=1, R=1;
        while ( R<i || L<=cnt)
        {
            if ( (R<i && ask[L].b>=E[R].b) || L>cnt) merge(E[R].x,E[R].y,E[R].a,E[R].b), ++R;
            else
            {
                for (int j=Beg[id[i]]; j<=End[id[i]]; ++j)
                    if (ask[L].b>=E[j].b && ask[L].a>=E[j].a) Stack[++top]=merge(E[j].x,E[j].y,E[j].a,E[j].b);

                int x=get(ask[L].x);
                if (x==get(ask[L].y)) ans[ask[L].k]=mxa[x]==ask[L].a && mxb[x]==ask[L].b;
                while (top) del();
                ++L;//Wrong Reason
            }
        }
    }

    for (int i=1; i<=q; ++i) puts(ans[i] ? "Yes" : "No");
    return 0;
}

概要

二つの質問を求めているため部分配列は、条件を満たしている必要があり、多くの場合、取消ブロックデータ構造を解決するために。

その後、ブロックサイズの最適化の複雑さを調整することができますか?

しかし、これは実際に私の結論でなく、私の研究ではなく、参照チームの主\(ブログを\)

おすすめ

転載: www.cnblogs.com/G-hsm/p/11461247.html