BZOJ 5415:[Noi2018]ツリー復興帰路のクラスカル

タイトル

\(〜\)
BZOJ 5415
LUOGU 4768
その長いタイトルは、我慢する必要はありません。

分析

二つの小さな感情:

  1. 私は、いくつかの大物は、この質問を聞いたので\(銅\にAgの\に)ために、\(SPFA \) そう、マップの否定的側面を経験していない後、または使用\(ダイクストラ\)それ。
  2. \(クラスカル\)ツリーは実際にそれの稀な知識に属するとみなされ、再構成\(BZOJ \)のみに(ネットワーク\)\ので、本当に真剣に学習アルゴリズムを、このアルゴリズムと呼ばれ、この時、ブラシタイトル金額は何かを表しています。

公式ソリューション:
この質問は、使用することです\(クラスカル\)ツリーの再構成を、なぜ?自然が決まります。\(クラスカル\)ツリーは、以下の良好な特性を持って再構築します:

  • エッジ以外のツリーのリーフノード点は、元のスパニングツリーに対応し、リーフノードは、元のスパニングツリー上のノードです。
  • 注文の新しいポイントと作成ので、右の上に元のスパニングツリーのサイズ(リーフノードを除く)ルートノードへの各点からそれを見つけることができるの周りを、ポイントが単調であるアクセスするために、右を指します。
  • ため\(クラスカル\)アルゴリズム本質的に貪欲であり、二点\(X \)\(Y \)\(LCA \)その右を指し、最小スパニングツリーボトルネックに対応します。
  • 実際には、このツリーは、バイナリヒープです。

この質問は、構築するためにどのようにしている\(クラスカル\)ツリーの再構成を?
最短の長さは、その後、自分自身を取得するためにこれを使用し、高度を左、アップケリ、建設降順た側の最初のキーの上昇を\(クラスカル\)再構成ツリー

各サブツリーのために、クエリがその後、サブツリーのルートの水線より下である場合、ツリー内のすべてのサブツリーのリーフノードが通信である場合他のサブツリーに、必要に応じてその風雲サブツリー出発点、点が費やす必要はありません。

現在の問い合わせのために、我々は、ルートノードをサブツリー見つかったと仮定する\(X- \) 満足(D [X]> P \を \) と\(D [FA [X] <= P \) と開始点(\をY \)サブツリー内の)、時間から\(Y \)リーフノードのいずれかのサブツリーへの直接アクセスを逸脱。

だから我々は、最小を過ごすために1ポイントから番号を選択する必要があるので、これは、リーフノードの数から使用します\(ダイクストラ\)最小との契約は、良いポイントにすべてのポイントを過ごす、この質問にも、完成です。

過去への完全なアイデア、ご参照くださいldxcaicai、笑のを:
その後、ストロークのアイデアを撫で。

  1. 私たちは、最初に直接ポイント・ツー・ポイント1あたりの最小コストを必要と\(Dijsktra + \)最短の前処理。
  2. 次いで、構築する(クラスカル\)\のツリーの再構成、及びこのツリー簡単の構築完了した後、部分木の最小コスト1点の距離のルートノードとして、各時点で維持\を(DFSは\)を取得します。
  3. 最後のポイントは、見つける方法です\(X- \)乗算アルゴリズム:、我々は重要なアルゴリズムのデビューをします。ダイレクトプラスポイント右\(>のp \)を掛けることができます木に制限されています。

コード

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int maxn=4e5+10,maxm=8e5+10,inf=0x3f3f3f3f;

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;
}

char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x)
{
    if (!x) *fe++=48;
    if (x<0) *fe++='-', x=-x;
    T num=0, ch[20];
    while (x) ch[++num]=x%10+48, x/=10;
    while (num) *fe++=ch[num--];
    *fe++='\n';
}

int vc[maxm<<1],Nc[maxm<<1],hc[maxn<<1],lc;
inline void addc(int x,int y)
{
    vc[++lc]=y,Nc[lc]=hc[x],hc[x]=lc;
}

struct Orz{int x,y,l,a;}e[maxm],p[maxn<<1];
inline bool cmp(Orz c,Orz d)
{
    return c.a>d.a;
}

int fa[maxn<<1];
inline int get(int x)
{
    return fa[x]==x?x:fa[x]=get(fa[x]);
}

int n,m,cnt,sum;
inline void Kruskal()
{
    cnt=n,sum=0;
    for (int i=1; i<=(n<<1); ++i) fa[i]=i;
    sort(e+1,e+m+1,cmp);
    for (int i=1; i<=m; ++i)
    {
        int x=get(e[i].x),y=get(e[i].y);
        if (x==y) continue;
        addc(++cnt,x),addc(cnt,y);
        fa[x]=fa[y]=cnt;
        p[cnt].a=e[i].a;
        if (++sum==n-1) break;
    }
}

int ver[maxm],edge[maxm],Next[maxm],head[maxn],len;
inline void add(int x,int y,int z)
{
    ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
    ver[++len]=x,edge[len]=z,Next[len]=head[y],head[y]=len;
}

int dist[maxn];
bool vis[maxn];
inline void Dijkstra(int s)
{
    memset(dist,0x3f,sizeof(dist));
    memset(vis,0,sizeof(vis));
    priority_queue<pii,vector<pii>,greater<pii> >q;
    q.push(make_pair(0,s)),dist[s]=0;
    while (!q.empty())
    {
        int x=q.top().second;
        q.pop();
        if (vis[x]) continue;
        vis[x]=1;
        for (int i=head[x]; i; i=Next[i])
        {
            int y=ver[i],z=edge[i];
            if (dist[y]>dist[x]+z)
            {
                dist[y]=dist[x]+z;
                q.push(make_pair(dist[y],y));
            }
        }
    }
    for (int i=1; i<=n; ++i) p[i].l=dist[i];
}

int f[maxn][20],d[maxn];
inline void dfs(int x,int pa)
{
    d[x]=d[pa]+1,f[x][0]=pa;
    for (int i=1; i<=19; ++i) f[x][i]=f[f[x][i-1]][i-1];
    for (int i=hc[x]; i; i=Nc[i])
    {
        int y=vc[i];
        dfs(y,x);
        p[x].l=min(p[x].l,p[y].l);
    }
}

inline int query(int x,int y)
{
    for (int i=19; i>=0; --i)
        if (d[x]-(1<<i)>0 && p[f[x][i]].a>y) x=f[x][i];
    return p[x].l;
}

inline void Clear()
{
    memset(f,0,sizeof(f));
    memset(d,0,sizeof(d));
    memset(head,0,sizeof(head));
    memset(hc,0,sizeof(hc));
    len=lc=0;
}

int main()
{
    int T;read(T);
    while (T--)
    {
        Clear();
        read(n);read(m);
        for (int i=1; i<=m; ++i) read(e[i].x),read(e[i].y),read(e[i].l),read(e[i].a),add(e[i].x,e[i].y,e[i].l);
        for (int i=n+1; i<=(n<<1); ++i) p[i].l=inf;
        Dijkstra(1);
        int Q,K,S;
        read(Q);read(K);read(S);
        Kruskal();
        dfs(cnt,0);
        int lastans=0;
        while (Q--)
        {
            int v,p;read(v);read(p);
            int x=(v+lastans*K-1)%n+1,y=(p+lastans*K)%(S+1);
            write(lastans=query(x,y));
        }
    }
    flush();
    return 0;
}

おすすめ

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