黒魔道士ドア(マジシャン) - 互いに素セット

タイトル

多忙の16日後に、人類の未来は、十分なエネルギーを集めています。しかし、戦争とバイオレットの惑星で、愚かさのZの副官ので、地球applepiのリーダーはバイオレットプラネットで投獄邪悪な黒魔術師Vaniです。ネスカフェに科学技術のこの野心的なプロジェクトを再起動するには、人類がXLK、Poet_shyのエリートチームを派遣しており、3人lydrainbowcat、タイムトンネルを通って、指導者がapplepi惑星バイオレットを保存する運命。一つだけドアapplepi投獄場所は、地元の人々は「黒魔術師の門。」それを呼び出します フリービューに権利がないドアに描か図パスワードのドアを開け、各点における度数の値がゼロより大きいとサブピクチャモジュロ十億九の偶数です。ここでサブグラフ(V、E)のように定義される:エッジEのV点セットとピクチャがEはVのエンドポイント側で任意のサブセットであります しかしVaniは、このパスワードが単純すぎだと思うので、ドア上のグラフは動的です。縁なしの図は、最初だけN頂点。ドア制御システムの協働構造Vani M回、エッジが図に追加されるたびに。あなたは偉大な指導者のapplepiを節約するために、刑務所の黒魔術師を開くことができるように、各操作の後に正しいパスワードを入力する必要があります。

入力出力

最初の行は二つの整数N及びMを含有します 次のM行は、各列二つの整数AとBは、ゲーティングシステムの代わりに自由縁部(A、B)を追加します。

Mの出力ラインの合計は、各操作パスワードを示します。

サンプル入力       

4 8        
3 1 
3 2 
2 1 
2 1 
1 3 
1 4 
2 4 
2 3

サンプル出力 

0 
0 
1 
3 
7 
7 
15 
31
問題の意味の説明:図の現在の状態の各出力は、エッジング後にサブピクチャの合計数を満たします。
問題解決のアイデア:この質問、多くのファン。まず第一に私が行う方法を考えていませんでした。しかし、私は何かビット出力を見つけました。サンプル出力が何であるかを簡素化: 0,1,3,7,15,31 。大声で教えてください、あなたは法律をまだ見つけて下さい! 私は見つけることができませんでした。 だから、明らかに、もちろん、それはシーケンス1の法則+ 2 *です。しかし、私はまた、すべての後に、プラス側は、サブグラフことを認識していなかった、答えはそれほど単純ではありませんことがわかりました。だから、ときに我々は答えを変更できますか?私たちは簡単に見つけるタイトル画像の明白な意味が子供の三角形を示し満たすことができます。三点、三辺。エッジの添加は、1 + 2 *でき、三角形を構成することができた後に、それは、です。
それでは、どのように三角形かどうかを判断するのですか?エンドポイントのこの新しい側面を決定することは非常に簡単で前に参加していなかった共通接続点を持っています。したがって、次のコードがあります。
書式#include <iostreamの> 
の#include <cstdioを> 
する#include <アルゴリズム> 
書式#include <CStringの> 
の#include <fstreamの> 
の#include < 設定 >
 の#defineは長い長いでしょ
 使用して 名前空間はstd;
int型読み取り(){
     int型 RES = 0、F = 1 char型のCH; 
    CH = GETCHAR()。
    一方、(CH < ' 0 ' || CH> ' 9 ' ){
         場合(CH == ' - ')F = - 1 
        CH = GETCHAR()。
    } 
    一方、(CH> = ' 0 ' && CH <= ' 9 ' ){ 
        RESの =のRES * 10 +(CH- ' 0 ' )。
        CH = GETCHAR()。
    } 
    戻り RES * F。
} 
のconst  int型 MAXN = 200005 constの LL MOD = 1000000009 ;
INTのN、M。
セット < 整数 >  U [MAXN]。
LL ANS; 
int型メイン(){ 
    N、M =; =(読み取り))(読み取ります。
    以下のためにint型 i = 1 ; iは= N <; ++ I)のu [i]は.insert(I)。
    以下のためにint型 I = 1 ; I <= M; ++ I){
         int型のCを、B。
        B = リード()。
        C = リード()。
        int型 FL = 0 ;
        セット < INT > ::イテレータITER = uは[B] .begin();!ITER = U [B] .END(); ++ ITER){
             int型 P = * ITER。
            もし(U [C] .count(P)){
                FL = 1 破ります; 
            } 
        } 
        U [B] .insert(C); U [C] .insert(B)。
        もし(FL)ANS = ANS * 2 + 1 
        printf(" %LLDする\ n " 、ANS)。
    } 
    FCLOSE(STDIN)。
    FCLOSE(STDOUT)。
    リターン 0 ; 
}
コードの表示

しかし、このコードの速度と精度を保証することは困難である、すべての後に、1個の環がまた再び更新を見つけることができるようになります提案を、満たすことです。絶対タイムアウト。

このように、私たちの互いに素-セットがあります。(ディスジョイントセットは私が書いていないものです)

同じコレクション内の両端場合では、同じコレクションに参加していない場合は、それ* + 1 2、、互いに素セットを使用して、答えを変更しません。

ACcode:

書式#include <iostreamの> 
の#include <cstdioを> 
する#include <アルゴリズム> 
書式#include <CStringの> 
の#include <fstreamの> 
の#include < 設定 >
 の#defineは長い長いでしょ
 使用して 名前空間はstd;
int型読み取り(){
     int型 RES = 0、F = 1 char型のCH; 
    CH = GETCHAR()。
    一方、(CH < ' 0 ' || CH> ' 9 ' ){
         場合(CH == ' - ')F = - 1 
        CH = GETCHAR()。
    } 
    一方、(CH> = ' 0 ' && CH <= ' 9 ' ){ 
        RESの =のRES * 10 +(CH- ' 0 ' )。
        CH = GETCHAR()。
    } 
    戻り RES * F。
} 
のconst  int型 MAXN = 200005 constの LL MOD = 1000000009 ;
INTのN、M。
INT [MAXN] F。
ANS LL; 
int型 find_f(int型X){
     戻り X == F [x]はx:F [X] = find_f(F [X])。
} 
int型のmain(){ 
    N)=(読み取り; M = 読み取ります()。
    以下のためにint型 i = 1 ; iは= N <; ++ I)F [I] = I。
    以下のためにint型 I = 1 ; I <= M; ++ I){
         int型のCを、B。
        B = リード()。
        C = リード()。
        INT Q = find_f(B)、P = find_f(C);
        もし(Q =!P){ 
            F [Q] =のC。
        } 
        ANS =(ANS * 2 + 1)%MOD。
        printf(" %LLDする\ n " 、ANS)。
    } 
    FCLOSE(STDIN)。
    FCLOSE(STDOUT)。
    リターン 0 ; 
}
コードの表示

しかし、それは今、私は非常にこのアプローチの正しさを証明することはできません。私は考えることができる唯一の説明は、同じセットの場合、2は新しく追加された側と、このパスが等価である。この時点で、ユニコムポイントを終わるパスを見つけるためにバインドされていることです。この時点で、その後の円を2点のみを構成する新たに追加されたパスの側面は、それが+1である新しいサブピクチャである。新たなエッジを追加し、そのパスを代わりに使用することができるが、その結果、二重元のプログラム。これは* 2です。


 
 

 

 

 

おすすめ

転載: www.cnblogs.com/clockwhite/p/11259945.html