1. 程式人生 > >「日常訓練」Duff in the Army (Codeforces Round #326 Div.2 E)

「日常訓練」Duff in the Army (Codeforces Round #326 Div.2 E)

題意(CodeForces 588E)

給定一棵\(n\)個點的樹,給定\(m\)個人(\(m\le n\))在哪個點上的資訊,每個點可以有任意個人;然後給\(q\)個詢問,每次問\(u\)\(v\)上的路徑有的點上編號最小的\(k(k \le 10)\)個人(沒有那麼多人就該有多少人輸出多少人)。

分析

\(u\)\(v\)上路徑的詢問很顯然的想到LCA,但是要維護前\(k\)在路徑上的最小的點似乎是個有點麻煩的問題。其實,找到了LCA(設為\(p\)點),我們就可以同樣的利用倍增的思想把\(u\)\(p\)\(v\)\(p\)點的路徑上的人全部求出(這裡有個小技巧,對於\(u\)

\(v\)點不妨錯開一層求,這樣可以避免去重的問題)。然後就是前\(k\)大了,這裡網上有的題解比較牛逼,起手一個主席樹,本資料結構廢物並不會,所以學習了一下CF的題解,採用了一種比較簡單的方法來處理(注意到\(k\)最大值不超過10)。

程式碼

經典的倍增線上求LCA板子。

#include <bits/stdc++.h>
#define rep(i,a,b) for(repType i=(a); i<=(b); ++i)
#define per(i,a,b) for(repType i=(a); i>=(b); --i)
#define ZERO(x) memset(x,0,sizeof(x))
#define MS(x,y) memset(x,y,sizeof(x))
#define PB emplace_back
#define MP make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef ll repType;

const int MAXN=100005;
const int MAXD=18;

vector<int> G[MAXN];
struct Node
{
    int a[11];
    Node() { MS(a, 63); }
    void
    insert(int x)
    {
        a[10]=x;
        sort(a, a+11);
    }
} vals[MAXD][MAXN];

Node
merge_node(const Node& x, const Node& y)
{
    Node ans=x;
    rep(i, 0, 10) { ans.insert(y.a[i]); }
    return ans;
}

int fa[MAXD][MAXN], d[MAXN];

void
dfs(int pre, int now)
{
    fa[0][now]=pre;
    rep(i, 1, MAXD-1)
    {
        fa[i][now]=fa[i-1][fa[i-1][now]];
        vals[i][now]=merge_node(vals[i-1][now], vals[i-1][fa[i-1][now]]);
    }
    rep(i, 0, int(G[now].size())-1)
    {
        int v=G[now][i];
        if(v!=pre)
        {
            d[v]=d[now]+1;
            dfs(now, v);
        }
    }
}

inline int
get_fa(int v, int k) // k=1, it will points to v _itself_.
{
    rep(i, 0, MAXD-1)
        if((1<<i) & k)
            { v=fa[i][v]; }
    return v;
}

int
LCA(int u, int v)
{
    if(d[u]<d[v]) { swap(u, v); }
    u=get_fa(u, d[u]-d[v]);

    if(u==v) { return u; }
    else per(i, MAXD-1, 0)
    {
        if(fa[i][u]!=fa[i][v])
        {
            u=fa[i][u];
            v=fa[i][v];
        }
    }
    return fa[0][v];
}

inline Node
get_people(int v, int k)
{
    Node ans;
    rep(i, 0, MAXD-1)
        if((1<<i) & k)
        {
            ans=merge_node(ans, vals[i][v]);
            v=fa[i][v];
        }
    return ans;
}

int
main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int n, m, q; cin>>n>>m>>q;

    rep(i, 1, n-1)
    {
        int u, v; cin>>u>>v;
        G[u].PB(v); G[v].PB(u);
    }
    rep(i, 1, m)
    {
        int c; cin>>c;
        vals[0][c].insert(i);
    }
    
    dfs(1, 1);
    rep(i, 1, q)
    {
        int u, v, k; cin>>u>>v>>k;
        int p=LCA(u, v);
        Node x=get_people(u, d[u]-d[p]); // it will get the point _below_ the LCA.
        Node y=get_people(v, d[v]-d[p]+1); // it will go through another route,
        Node ans=merge_node(x, y);         // if not, y _itself_ must be the LCA,
        int tmp=0;                         // and the y will be the value of V.
        while(tmp<k && ans.a[tmp]<=m) { tmp++; }
        k=tmp;
        cout<<k;
        rep(i, 0, k-1) cout<<" "<<ans.a[i];
        cout<<endl;
    }
    return 0;
}