羅区P3998 [SHOI2013]マイクロボー

羅区P3998 [SHOI2013]マイクロボー

羅区ポータル

タイトル説明

SHのマイクロブログは、ちょうど、この短い月の時点では、n個のユーザー(1Lnラベル)の合計をオープンしました

彼らは頻繁にユーザーが、時系列順にm個のレコードの合計です。

! x 表示用户x发了一条微博;
+ x y 表示用户x和用户y成为了好友
− x y 表示用户x和用户y解除了好友关系

ときにすべての彼の友人(直接の関係は)彼のメッセージが表示されますユーザーマイクロボー、。

誰もが関係の始まりは友人ではないとの間で、また、記録されていると仮定したときに法的(すなわち+ XY xと

)のxy xとyは友人でなければならない - yが、友人はならない、と。

このMレコードに出現を求めた後、各ユーザーはどのように多くのメッセージを表示します。

入力形式

1行目二つの整数N、M。

その後で、タイトルとして各レコード形式、行のM及びMは、時系列レコードに読み取られます

スペースで区切られています。

出力フォーマット

n個(線のない空間側)のスペースで区切られた出力線は、最後のIを参照するに、i番目のユーザを表します

いくつかのメッセージ。

サンプル入力と出力

入力#1コピー

出力#1コピー

説明/ヒント

N <= 200000

M <= 500000

ソリューション:

10のシミュレーションゲームの2019組(こんにゃくは、テスト受験文化研究に震えています)

その後@littleseven 7兄弟はこの質問を行うに連れて行ってくれました...

当時暴力のアイデア、そして考えることは非常に簡単のうちわずか50ポイント、それは配列開くことです(F [i] [j]が\)\を(オープンブール配列は、あなたには、いくつかのスペースを節約することができ、それができるよう開くようにしましょう\(10 ^ 8 \) )、を表す\を(私は\)、\ (J \)は友人ではありません。その後、誰かのメッセージ、すべての私の友人への答えでそれを置くたびに\(+ 1 \)

50ptsコードは、次のとおりです。

#include<cstdio>
#include<iostream>
using namespace std;
int n,m;
bool f[10000][10000];
int ans[10000];
int main()
{
    // freopen("qq.in","r",stdin);
    // freopen("qq.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        char ch;
        cin>>ch;
        if(ch=='+')
        {
            scanf("%d%d",&x,&y);
            f[x][y]=1,f[y][x]=1;
        }
        else if(ch=='-')
        {
            scanf("%d%d",&x,&y);
            f[x][y]=0,f[y][x]=0;
        }
        else
        {
            scanf("%d",&x);
            for(int j=1;j<=n;j++)
                if(f[x][j])
                    ans[j]++;
        }
    }
    for(int i=1;i<=n;i++)
        printf("%d ",ans[i]);
    return 0;
}

そして、正の解を教えて。

上部にさらに綿密な表情が正の解であれば実際には、私は暴力を考え、アイデアがあります:録音友人、累積答え上記のコードは、暴力と呼ばれる理由は複雑さは同じではありませんのでので、次のコードは、正の解と呼ばれています。正のソリューションは、大規模なデータを実行することができます。したがって、この問題ではなく、私たちの診察室での解答テクニックを教える:我々は唯一の暴力のアイデアを考え出すことができる場合には、公知の手段によって暴力の最適化アルゴリズムは、おそらく実際に従事する方法を考えるには、正のソリューションを出てきました。

以下、ストレートポイントにシリアのゴシップ:

録音友人、累積答え:私たちは、暴力の考え方になってきました。私たちはただの友達のレコードは、マトリクスアレイを開くことであろう使用しました。しかし、これは確かに劣らず、オープンスペースではありません(\(N- \ル2 \ ^ 10. 5回\) )。だから我々は考えるようになった:私たちはどうすることができます\(1-n個\)誰もがシーケンスを記録しますが、簡単にそれを追加および削除できますか?

\(STLの\)大法:\(SET \)コンテナ。

使用\(セット\)をコードは、2つのポイントの残りの80点となる\(TLE \)

80ptsコードは、次のとおりです。

#include<cstdio>
#include<iostream>
#include<set>
using namespace std;
const int maxn=2*1e5+1;
int n,m;
set<int> s[maxn];
set<int>::iterator it;
int ans[maxn];
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int read()
{
    int x=0,f=1;
    char ch=nc();
    while(ch<48){if(ch=='-')f=-1;ch=nc();}
    while(ch>47)    x=x*10+ch-'0',ch=nc();
    return x*f;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        int x,y;
        char ch=nc();
        if(ch=='+')
        {
            x=read();y=read();
            s[x].insert(y);
            s[y].insert(x);
        }
        else if(ch=='-')
        {
            x=read();y=read();
            s[x].erase(y);
            s[y].erase(x);
        }
        else
        {
            x=read();
            for(it=s[x].begin();it!=s[x].end();it++)
                ans[*it]++;
        }
    }
    for(int i=1;i<=n;i++)
        printf("%d ",ans[i]);
    return 0;
}

プラスの最適化を読んで、しかし、使用していませんでした......

その後、我々は考えるように続ける......

以来\(TLE \) その後、明らかに、ときの統計の質問への答え。イテレータに最初から最後まで統計を使用してのアイデアへの答え80、\(X \)各回答の\(1 + \)は、この複雑さがほとんどです\(O(n回mを\ )\) 明らかにそれは動作しません。

だから我々はこのことを考慮してくださいません一度プラスので、一度私たちは束を追加します。

原則の具体的な実現はこれです:

想像してみて、今、あなたは請負業者が、あなたは作業者、賃金1日1ドルを与える必要があります。そしてある日〜男が終了するので、あなたは彼に、これらの日は、あなたが幸せに爆破彼の賃金との和解を与えます

この質問への移行は:あなたがより多くのたびに、ブログと、サイトの同等は別の日に住んでいた、あなたはあなたの労働者(友人が)賃金のドルを作っ与えたいです。あなたは、決済あまりにも面倒で1日だと思うので、あなたは、それらへのマネー決済で、昼と退職の日を仕事に各ワーカーの最初の日を記録してください。

これは、差分がそれを考えています!

私たちは、アレイ開かれた\を(CNT [i]が\) 今、まで表現\は(私は\)マイクロブログの数をしました。人は追加すると\(私は\)友人を、この人が追加何時間記録(私は\)\を、具体的な方法がすることです(CNT [i]が\)\減算され、取り外したときに\(私は)\その後、削除するときに、友人を\(CNTを[I] \)バック追加しました。このように、\(CNTは、[I_1] \)\(CNT [I_2] \)の人に代わって、違いになるために(私は\)\マイクロブログの友人の数は、この期間内に受信しました。

もちろん、この処理された\(m個\)まだ友達であるいくつかの他の人があるだろうとき番目に依頼します。当社の統計的アルゴリズムは、削除されたとき、友人に答えます。これは、サイトが倒産した一日と同じですが、あなたのパンツはまた、それらにお金を与える必要が場合でも、あなたに従うことを、いくつかの労働者が残っています。

私たちはただ、処理中に、ズボンを必要としない場合は、この質問です\(m個\)に加えて、二重の操作後に\(\用)答えることを余儀なく統計ループ。

(個人的に私はあなたが思うならば、あなたが理解して良好な画像がああ、このアナロジーは、それは私が簡単に〜祈り、賛美することをお勧めしますことを、便利だと思います)

100ptsコードは、次のとおりです。

#include<cstdio>
#include<set>
#include<iostream>
using namespace std;
const int maxn=2*1e5+1;
int n,m;
int cnt[maxn],ans[maxn];
set<int> s[maxn];
set<int>::iterator it;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        char opt;
        cin>>opt;
        int x,y;
        if(opt=='!')
        {
            scanf("%d",&x);
            cnt[x]++;
        }
        else if(opt=='+')
        {
            scanf("%d%d",&x,&y);
            ans[x]-=cnt[y];
            ans[y]-=cnt[x];
            s[x].insert(y);
            s[y].insert(x);
        }
        else
        {
            scanf("%d%d",&x,&y);
            ans[x]+=cnt[y];
            ans[y]+=cnt[x];
            s[x].erase(y);
            s[y].erase(x);
        }
    }
    for(int i=1;i<=n;i++)
        for(it=s[i].begin();it!=s[i].end();it++)
            ans[i]+=cnt[*it];
    for(int i=1;i<=n;i++)
        printf("%d ",ans[i]);
    return 0;
}

おすすめ

転載: www.cnblogs.com/fusiwei/p/11693977.html