「日常訓練」Duff in the Army (Codeforces Round #326 Div.2 E)
阿新 • • 發佈:2018-11-09
題意(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\)
程式碼
經典的倍增線上求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; }