2019年7月23日(グラフ理論)

ほとんどの水波テスト!

そして、水は次のようになります。
ただ、いくつか取る\(SBの\)ポイントを、他はする(JJの\)\します最も憂鬱です\(T1 \) 水が前後に二時間以上なかった\(\ YY)出て、落ち込んでああ!

あるいは話の最も簡単に起動します。

prob2:問題の木(ツリー)

タイトル効果:無根木与えられた(Mの\)を\クエリ、それぞれが所定の\(\)\(B \) このようなツリーシーク全ての形態の\(\)がある\ (B \)祖先または\(B \)である(\)\祖先プログラム番号。

\(SBの\)質問、単にポイント、典型的な赤のタイトルを取得。取得\(\)をし、\(B \)\(LCA \) 判定\(\)\(B \)はに等しい(LCA \)を\、サブ両方によるその後の分類規則ツリー\(サイズ\)答えを計算します

コードを見てください:

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#define xx 210000
inline int read()
{
    int x=0,f=1;char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
vector<int>e[xx];
struct point{ll sz,top,dep,fa,son;bool vis;}dot[xx];
inline void dfs1(int g)
{
    dot[g].sz=1;
    fur(i,0,(int)e[g].size()-1)
    {
        if(!dot[e[g][i]].vis)
        {
            dot[e[g][i]].vis=true;
            dot[e[g][i]].fa=g;
            dot[e[g][i]].dep=dot[g].dep+1;
            dfs1(e[g][i]);
            dot[g].sz+=dot[e[g][i]].sz;
            if(dot[dot[g].son].sz<dot[e[g][i]].sz) dot[g].son=e[g][i];
        }
    }
}
inline void dfs2(int g,int gg)
{
    dot[g].top=gg;
    if(dot[g].son) dfs2(dot[g].son,gg);
    fur(i,0,(int)e[g].size()-1) if(e[g][i]!=dot[g].son&&e[g][i]!=dot[g].fa) dfs2(e[g][i],e[g][i]);
}
inline int lca(int u,int v)
{
    while(dot[u].top!=dot[v].top)
    {
        if(dot[dot[u].top].dep<dot[dot[v].top].dep) swap(u,v);
        u=dot[dot[u].top].fa;
    }
    if(dot[u].dep<dot[v].dep) return u;
    else return v;
}
inline int llca(int u,int v)
{
    int before;
    while(dot[u].top!=dot[v].top) before=v,v=dot[dot[v].top].fa;
    if(v!=u) return dot[u].son;
    else return dot[before].top;
}
int main()
{
    int n=in,m=in;
    fur(i,1,n-1)
    {
        int x=in,y=in;
        e[x].push_back(y);
        e[y].push_back(x);
    }
    dot[1].vis=true;
    dfs1(1);
    dfs2(1,1);
    fur(i,1,m)
    {
        int x=in,y=in;
        int z=lca(x,y);
        if(z!=x)
        {
            if(z!=y) printf("%lld\n",dot[x].sz+dot[y].sz);
            else printf("%lld\n",n-dot[llca(y,x)].sz+dot[x].sz);
        }
        else printf("%lld\n",n-dot[llca(x,y)].sz+dot[y].sz);
    }
    return 0;
}

prob3:饗宴(パーティ)

タイトル効果:連結グラフが与えられると、与えられた固定小数点と固定長の2対の固定点間の最短経路は、固定長を超えていないことなどの多くのエッジを削除し、削除された出力側まで。

\(マイ\) \(solutin \) まあ、私はこの質問には、審査半書き込み萎凋病は、結果が走っていなかったとき、水だけの単純だと思います \(50 \)ポイント。もともとかもしれないと思った(T \)を\飛ぶことが、後に良い結果を見つけました。試験場合は、データが半分のポイントにこの水を取ることができ、複雑さと正確性が完全に間違っているが、しかし、その後、ボーダー暴力の波が(後にできるはずですが、実際は、の一部があるでしょうです \(T \)飛ぶことを、得点することが期待されている \ (70 \)またはそう)、疲れた心、コード上:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;i++)
#define xx 3300
#define inf 0x7f
inline int read()
{
    int x=0,f=1;char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
int dis1[xx],dis2[xx],pre1[xx],pre2[xx];
vector<int>e[xx];
bool lt[xx][xx],vis1[xx],vis2[xx],key;
int id[xx][xx],pk[xx];
deque<int>q;
inline void spfa(int s,int *dis,bool *vis,int *pre)
{
    dis[s]=0;
    vis[s]=true;
    q.push_back(s);
    while(!q.empty())
    {
        int g=q.front();
        vis[g]=false;
        q.pop_front();
        fur(i,0,(int)e[g].size()-1)
        {
            if(lt[g][e[g][i]])
            {
                if(dis[e[g][i]]>dis[g]+1)
                {
                    dis[e[g][i]]=dis[g]+1;
                    pre[e[g][i]]=g;
                    if(!vis[e[g][i]])
                    {
                        vis[e[g][i]]=true;
                        if(!q.empty())
                        {
                            if(dis[e[g][i]]<=dis[q.front()]) q.push_front(e[g][i]);
                            else q.push_back(e[g][i]);
                        }
                        q.push_back(e[g][i]);
                    }
                }
            }
        }
    }
}
struct edge{int id,u,v,num;}ee[xx<<1];
inline void init()
{
    memset(dis1,inf,sizeof(dis1));
    memset(dis2,inf,sizeof(dis2));
    memset(pre1,0,sizeof(pre1));
    memset(pre2,0,sizeof(pre2));
    memset(vis1,false,sizeof(vis1));
    memset(vis2,false,sizeof(vis2));
}
inline bool cmp(edge x,edge y){return x.num<y.num;}
inline void handle(int t1,int t2,int all)
{
    while(pre1[t1])
    {
        ee[id[pre1[t1]][t1]].num++;
        t1=pre1[t1];
    }
    while(pre2[t2])
    {
        ee[id[pre2[t2]][t2]].num++;
        t2=pre2[t2];
    }
    sort(ee+1,ee+all+1,cmp);
}
inline bool check(int now,int s1,int s2,int t1,int t2,int l1,int l2)
{
    fur(i,1,now)
    {
        lt[ee[i].u][ee[i].v]=false;
        lt[ee[i].v][ee[i].u]=false;
    }
    init();
    spfa(s1,dis1,vis1,pre1);
    spfa(s2,dis2,vis2,pre2);
    fur(i,1,now)
    {
        lt[ee[i].u][ee[i].v]=true;
        lt[ee[i].v][ee[i].u]=true;
    }
    if(dis1[t1]>l1||dis2[t2]>l2) return false;
    else return true;
}
inline bool checked(int *u,int now,int s1,int s2,int t1,int t2,int l1,int l2)
{
    fur(i,1,now)
    {
        lt[ee[u[i]].u][ee[u[i]].v]=false;
        lt[ee[u[i]].v][ee[u[i]].u]=false;
    }
    init();
    spfa(s1,dis1,vis1,pre1);
    spfa(s2,dis2,vis2,pre2);
    fur(i,1,now)
    {
        lt[ee[u[i]].u][ee[u[i]].v]=true;
        lt[ee[u[i]].v][ee[u[i]].u]=true;
    }
    if(dis1[t1]>l1||dis2[t2]>l2) return false;
    else return true;
}
inline void ck(int m,int now,int here,int need,int s1,int s2,int t1,int t2,int l1,int l2)
{
    if(key) return;
    if(now==need)
    {
        if(checked(pk,now,s1,s2,t1,t2,l1,l2)) key=true;
        return;
    }
    fur(i,here,m)
    {
        pk[now+1]=i;
        if(now+1+m-i<need) return;
        ck(m,now+1,here+1,need,s1,s2,t1,t2,l1,l2);
    }
}
int main()
{
    int n=in,m=in,all=0;
    fur(i,1,m)
    {
        int x=in,y=in;
        e[x].push_back(y);
        e[y].push_back(x);
        lt[x][y]=true;
        lt[y][x]=true;
        id[y][x]=id[x][y]=++all;
        ee[all].u=x;
        ee[all].v=y;
        ee[all].id=all;
        ee[all].num=0;
    }
    int s1=in,t1=in,l1=in;
    int s2=in,t2=in,l2=in;
    init();
    spfa(s1,dis1,vis1,pre1);
    spfa(s2,dis2,vis2,pre2);
    if(dis1[t1]>l1||dis2[t2]>l2)
    {
        printf("That's all trouble!\n");
        return 0;
    }
    handle(t1,t2,all);
    int ans=0,L=0,R=m;
    while(L<R)
    {
        int mid=(L+R)>>1;
        if(check(mid,s1,s2,t1,t2,l1,l2)) ans=mid,L=mid+1;
        else R=mid-1;
    }
    ck(m,0,1,ans+1,s1,s2,t1,t2,l1,l2);
    if(key) ans++;
    printf("%d\n",ans);
    return 0;
}

ポジティブな解決策:最初の\(\ ORZ)先輩が波

上の2点間の指定されたパスを取得する、非常に巧妙な考え\(DIS(S1、T1) \) と$
DIS(S2、T2) 二\の間に重複部分が提供される)\ P1 \(および\) P2 \(、我々は要求され\) DIS(S1、T1)
+ DIS(S2、T2)、DIS(P1、P2)$の最小(右側があるので\(1 \) そう使用上方エッジの総数を保存する
式はエッジの数を取得するために削除することができる発現最大値が最小となるように対象がはるかに容易であるように、)

コードの場合:

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define xx 3100
inline int read()
{
    int x=0,f=1;char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
int dis[xx][xx],vis[xx];
queue<int>q;
vector<int>e[xx];
inline void bfs(int s)
{
    dis[s][s]=0;
    vis[s]=s;
    q.push(s);
    while(!q.empty())
    {
        int g=q.front();
        q.pop();
        fur(i,0,(int)e[g].size()-1)
        {
            if(vis[e[g][i]]!=s)
            {
                dis[s][e[g][i]]=dis[s][g]+1;
                vis[e[g][i]]=s;
                q.push(e[g][i]);
            }
        }
    }
}
int main()
{
    int n=in,m=in;
    fur(i,1,m)
    {
        int x=in,y=in;
        e[x].push_back(y);
        e[y].push_back(x);
    }
    memset(dis,0x7f,sizeof(dis));
    fur(i,1,n) bfs(i);
    int s1=in,t1=in,l1=in;
    int s2=in,t2=in,l2=in;
    if(dis[s1][t1]>l1||dis[s2][t2]>l2)
    {
        puts("That's all trouble!");
        return 0;
    }
    int ans=dis[s1][t1]+dis[s2][t2];
    fur(i,1,n)
    {
        fur(j,1,n)
        {
            if(dis[i][j]+dis[s1][i]+dis[j][t1]<=l1&&dis[i][j]+dis[j][t2]+dis[s2][i]<=l2)
                ans=min(ans,dis[i][j]+dis[s1][i]+dis[j][t1]+dis[j][t2]+dis[s2][i]);
            if(dis[j][i]+dis[s1][j]+dis[i][t1]<=l1&&dis[j][i]+dis[s2][i]+dis[j][t2]<=l2)
                ans=min(ans,dis[j][i]+dis[s1][j]+dis[s2][i]+dis[i][t1]+dis[j][t2]);
        }
    }
    printf("%d\n",m-ans);
    return 0;
}

もちろん、上述した手順は、好ましくは、代わりに隣接リストのに使用される\(ベクトル\) 検査\(ベクトル\)カードの危険性があります

prob1:カウントポイント(XDIS)

タイトル効果:与えられた最小の費用で他のパスのコストの右側を介して別の点は、パスの最大値として定義される無向グラフ、右側エッジストリップ、および最短一点、最短長見つける\(X \)は点の数であります

ポジティブなソリューション:波ため息再び\(ljq \)知能首長、と彼は深く感銘を受けました。

質問の右側の整数であり、かつ長さが\(X \)が直接求めているのではなく、超えないの長さを取得するために\(X \)をより大きく(しかし、うまく\(のx \)側ブロックサイズがリンクである場合、ブロックのサイズを計算ユニコム残りの側は、形成されている、省略されている\(cnt_i \)させ、その後、\(C_ {cnt_i} ^ 2 \) それについて考えるへの寄与を、あなたが最初の最短経路を計算することができますので、これは、)右証明するのは難しいことではありませんより大きいではありません\(X \)そして、最短パスを計算することはより大きくありませんが、ポイント数である\(X-1 \)解決しやすい番号、をポイントします。

私も何を実行するために、検査室の結果に行きました\(SPFA \)をブラインドプッシュにも、どのような式の波を、最終的な表面\(T \)飛ぶ、無\(Tが\)もいっぱいです(WA \)\ ......

コード上で、悲しいことに、と言う(またはあまりにも多くの食べ物、そしてちょうど長い時間のための互いに素-トーンセットを持って)しないでください。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;i++)
#define xx 330000
#define ll long long
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
struct edge{ll u,v,val;}d[xx];
ll fa[xx],n,m,cnt[xx];
inline ll find(int x){return (fa[x]==x)?x:(fa[x]=find(fa[x]));}
inline bool cmp(edge x,edge y){return x.val<y.val;}
inline ll sol(ll x)
{
    fur(i,1,n) fa[i]=i,cnt[i]=0;
    fur(i,1,m)
    {
        if(d[i].val>x) break;
        if(find(fa[d[i].u])!=find(fa[d[i].v])) fa[find(d[i].u)]=find(d[i].v);
    }
    fur(i,1,n) cnt[find(i)]++;
    ll res=0;
    fur(i,1,n) if(cnt[i]) res+=cnt[i]*(cnt[i]-1)/2;
    return res;
}
int main()
{
    n=in,m=in;
    ll k=in;
    fur(i,1,m)
    {
        ll x=in,y=in,z=in;
        d[i]=(edge){x,y,z};
    }
    sort(d+1,d+m+1,cmp);
    ll ans1=sol(k);
    ll ans2=sol(k-1);
    printf("%lld\n",ans1-ans2);
    return 0;
}

注意してください!注意してください!高エネルギーフロント

しかし、最も困難な問題は、データのほとんど水があります(ので、この質問は実際にはそれほど嫌ではありません)。

prob4:最小スパニングツリー(グラフ)

タイトル効果:私は持つようになった(\ N-)\を、m個の操作の後、三種類の合計は、操作数が設定されている図には側面が存在しない、ノード\(Iは\) まず、\は(ADD( B)\)として(B \)\の間の長さ追加\を(私は\)側、第二\は((k)を削除\)を削除正面である\(K \)の主要な側面を、そして最後に一種の\(リターン\)の回避のために、\(I-1 \)キー操作は、操作がされていないことを確実にするために\(RETURNを\) スパニングツリー図最小の重みの和の出力側の各操作の後、最小スパニングツリー、出力無し\(0 \)

単調なキュー、結果をやりたいようになりました\(CE \) ......が、残念ながら、

その後、先輩が言います吸盤タイトルは、アイデアは私が(恥知らず)が見つかりだけのようなことを、非常に簡単です。しかし、その後、彼はので、時間不足の実用化(両方に従事していなかった\(T1 \) ああ!!)。

無力怒り......

またはバーに話す、正のソリューションは:まず、3つのプロパティクリアするには:\(1 \)を 1辺が選択されていない場合、彼らが参加するときに最小全域木、彼が選択されることはありません。\(2 \)を削除します唯一の追加最後のエッジ穿刺\(K \)エッジを; \(3 \する)だけ前のバージョンに戻す戻ります。最初のプラス側を形成した後、スパニングツリーには影響しないので、すべての瞬間に答える記録し、使用前にそう:通常3上の問題を解決するだけでなく、この問題は強制的なオンラインを必要としないため、その後、明確なテンプレートが発生するのを助けますそれは答えの正しさには影響しない、とエッジが(覚えて破棄することができます\(タグ\を)状態を消去し、最後の追加に削減されます。)、まだスパニングツリー成形、暴力的な実行をするとき、\(K \)の前にエッジ以前の記録は良いですが、プラス一側プラス側の失効、暴力の再実行、そして国境消去が取り消され、ポップアップし、彼らがすることができます取り消さ;状態、答えは答えを持つので、記録されている(YYの\を)\あらかじめ用意されていどちらのうち、代わりに答え。\(ljqの\は)言った: "難易度は大きくはありません。"

主なポイント:2の互いに素セットの最適化 - ランク合併により、

サブツリーによって\(サイズ\)時間を節約するために、高圧縮を実現するために、大きさは形而上学ツリー

(Tucaoデータがあり、見て(30 \)\(唯一の副部品分割\(\)を追加)の操作を、この動作のためのコードがあまりにもあってもよいレイアウトする(90 \)\点、このデータは、Tucao水に単にできませんでした真香、サンプルの回答を見てはいるように見える(m個\)\ \(0 \) このデータのために、そして私が持っていた\(CEを\))......、その場で死亡しました

コードの場合:

#include<iostream>
#include<cstdio>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;i+=1)
#define ll long long
#define xx 500010
inline int read()
{
    int x=0,f=1;char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
ll fa[xx],sta[xx],ans[xx],id[xx],sz[xx];
bool choose[xx];
struct prom{ll u,v,op,k;}b[xx];
inline ll find(ll x){return fa[x]?find(fa[x]):x;}
int main()
{
    ll n=in,m=in,top=0,cnt=0,length=0;
    char ch[10];
    fur(i,1,n) sz[i]=1;
    fur(i,1,m)
    {
        scanf("%s",ch);
        if(ch[0]=='R') b[i].op=3;
        if(ch[0]=='A') b[i].op=1,b[i].u=in,b[i].v=in;
        if(ch[0]=='D') b[i].op=2,b[i].k=in;
    }
    fur(i,1,m)
    {
        if(b[i].op==1)
        {
            ll a=find(b[i].u),c=find(b[i].v);
            if(sz[a]>sz[c]) swap(a,c);
            id[++top]=i;
            sta[top]=a;
            if(a!=c)
            {
                fa[a]=c;
                sz[c]+=sz[a];
                ++cnt;
                length+=i;
                choose[i]=true;
            }
            if(cnt>=n-1) ans[i]=length;
        }
        if(b[i].op==2)
        {
            if(b[i+1].op!=3)
            {
                fur(j,1,b[i].k)
                {
                    if(choose[id[top]])
                    {
                        --cnt;
                        length-=id[top];
                        sz[fa[sta[top]]]-=sz[sta[top]];
                        fa[sta[top]]=0;
                    }
                    top-=1;
                }
                if(cnt>=n-1) ans[i]=length;
            }
            else ans[i]=ans[id[i-b[i].k+1]-1];
        }
        if(b[i].op==3)
        {
            if(b[i-1].op==1)
            {
                if(choose[id[top]])
                {
                    --cnt;
                    length-=id[top];
                    sz[fa[sta[top]]]-=sz[sta[top]];
                    fa[sta[top]]=0;
                }
                top-=1;
            }
            ans[i]=ans[i-2];
        }
        printf("%lld\n",ans[i]);
    }
    return 0;
}

ああ、長い書かれた問題へのこの予想外の解決策、停止したいと考えています\(とdabai \) A

おすすめ

転載: www.cnblogs.com/ALANALLEN21LOVE28/p/11312981.html