其他分享
首页 > 其他分享> > 【CF1320E】 Treeland and Viruses 题解

【CF1320E】 Treeland and Viruses 题解

作者:互联网

CF 传送门:CF1320E

虚树 + dijkstra。

解法来自 @hs_black

Solution

1

发现 \(m\) 的总和与 \(n\) 同级。又因为每次询问只涉及到少数节点,故知道使用虚树去优化。

建虚树优化什么?动态规划似乎不太可做,而病毒感染的过程有些像最短路。

最短路,使用 \(\text{spfa}\)?但 \(\text{spfa}\) 是无序的,而病毒感染是有序的,也即是说,使用 \(\text{spfa}\) 可能会让某些节点挡住病毒过不去,但实际上病毒可以继续感染。

\(\text{spfa}\) 因为无序而不能使用,那就自然想到使用 \(\text{dijkstra}\)。它有优先队列维护,故我们可以自定义优先级。

2

显然,当前进行的轮数是第一关键字。轮数小的肯定优先被选取。然后在同一轮中,病毒感染的优先级受病毒序号大小的影响。故病毒序号是第二关键字。

那如果两个节点的轮数相同、染上的病毒也相同,我们该优先选择哪个?我们现在在跑最短路,而病毒感染又受两点间路径长度的影响(每个病毒有个参数 \(s_i\)),故第三关键字是病毒在此轮中还能传染的路径长度。

有了这三个关键字,我们就可以开始跑最短路了。

3

讲一些实现的细节。

因为虚树涉及到两点 \(\text{LCA}\) 以及每点的时间戳,而且最短路中还要求树上两点间距离,所以使用树链剖分实现。

在建虚树的时候会先扔一个 \(1\) 号节点进去,尽管题目中并没说 \(1\) 号节点是什么关键节点或者根节点。原因是 \(1\) 号节点是我们假定的一个根,从它开始建虚树,这对最终答案并不影响,不过我们在计算完答案初始化的时候能因此简化很多繁琐的特判。

Code

鄙人不才,写的时候将函数归类了一下,看起来整齐简洁了点,希望能让它方便理解些。

#include<bits/stdc++.h>
using namespace std;
 
#define rep(i, a, b) for(register int i = a; i <= b; ++i)
const int maxn = 2e5 + 5;
int n, qst;
int hd[maxn], cnt;
struct edge{int to, nxt;}oe[maxn << 1];
int sz[maxn], mxs[maxn], fa[maxn], dep[maxn];
int tp[maxn], dfn[maxn], tot;
int a[maxn], st[maxn], top;
vector <int> ve[maxn];
int ask[maxn];
struct pnts{
    int col, v, di, ti;
    bool operator <(const pnts &y) const{ return (ti != y.ti ? (ti < y.ti) : (col != y.col ? (col < y.col) : (di > y.di)));}
}vr[maxn], I;
struct que{
    pnts p; int x;
    bool operator <(const que &j) const { return j.p < p; }
}; priority_queue <que> q;
//-----------------------------------------------
inline void addo(int u, int v){oe[++cnt] = (edge){v, hd[u]}; hd[u] = cnt;}
inline void dfs1(int u, int f){
    fa[u] = f, dep[u] = dep[f] + 1, sz[u] = 1;
    for(int v, i = hd[u]; i; i = oe[i].nxt){
        if((v = oe[i].to) == f) continue;
        dfs1(v, u), sz[u] += sz[v];
        if(sz[mxs[u]] < sz[v]) mxs[u] = v;
    }
}
inline void dfs2(int u, int anc){
    tp[u] = anc, dfn[u] = ++tot;
    if(!mxs[u]) return; dfs2(mxs[u], anc);
    for(int v, i = hd[u]; i; i = oe[i].nxt)
        if((v = oe[i].to) ^ fa[u] and v ^ mxs[u]) dfs2(v, v);
}
inline int LCA(int x, int y){
    while(tp[x] != tp[y]){
        if(dep[tp[x]] < dep[tp[y]]) swap(x, y);
        x = fa[tp[x]];
    } return dep[x] < dep[y] ? x : y;
}
//----------------Tree_Chain---------------------
inline bool cmp(int x, int y){return dfn[x] < dfn[y];}
inline void addv(int u, int v){ve[u].push_back(v), ve[v].push_back(u);}
inline void insrt(int x){
    int lca = LCA(x, st[top]);
    if(top == 1 or lca == st[top]){st[++top] = x; return;}
    while(top > 1 and dfn[st[top - 1]] >= dfn[lca]) addv(st[top - 1], st[top]), top -= 1;
    if(lca ^ st[top]) addv(st[top], lca), st[top] = lca;
    st[++top] = x;
}
inline void build(int tm, int k){
    rep(i, 1, tm)
        scanf("%d", &a[i]), scanf("%d", &vr[a[i]].v),
        vr[a[i]].col = i, vr[a[i]].ti = 0, q.push((que){vr[a[i]], a[i]});
    rep(i, 1, k) scanf("%d", &ask[i]), a[++tm] = ask[i];
    sort(a + 1, a + tm + 1, cmp); 
    st[top = 1] = a[0] = 1;
    rep(i, 1, tm) if(a[i] != a[i - 1]) insrt(a[i]);
    while(top > 0) addv(st[top - 1], st[top]), top -= 1;  
}
inline void init(int x, int f){
    for(auto nxt : ve[x]) 
        if(nxt ^ f) init(nxt, x);
    ve[x].clear(), vr[x] = I;
}
//----------------Virtual_Tree-------------------
inline int dis(int x, int y){return dep[x] + dep[y] - 2 * dep[LCA(x, y)];}
inline pnts updt(int lst, int nw){
    int d = dis(lst, nw); pnts rec = vr[lst];
    if(d <= vr[lst].di){rec.di -= d; return rec;}
    d -= vr[lst].di; int dt =  (d - 1) / vr[lst].v + 1;
    rec.di = dt * vr[lst].v - d, rec.ti += dt;
    return rec;
}
inline void dijkstra(){
    while(!q.empty()){
        que nw = q.top(); q.pop();
        if(vr[nw.x] < nw.p) continue;
        for(auto nxt : ve[nw.x]){
            pnts tmp = updt(nw.x, nxt); 
            if(tmp < vr[nxt])
                vr[nxt] = tmp, q.push((que){vr[nxt], nxt});
        }
    }
}
//----------------Dijkstra-----------------------
int main(){
    scanf("%d", &n); 
    rep(i, 2, n){
        int x, y; scanf("%d%d", &x, &y);
        addo(x, y), addo(y, x);
    } dfs1(1, 0), dfs2(1, 1);   
    I.col = I.ti = n + 1; rep(i, 1, n) vr[i] = I;
    scanf("%d", &qst);
    while(qst--){
        int k, m; scanf("%d%d", &m, &k);
        build(m, k), dijkstra();
        rep(i, 1, k) printf("%d ", vr[ask[i]].col);
        printf("\n"), init(1, 0);
    }
    return 0;
}

感谢阅读。

标签:int,题解,top,CF1320E,st,dep,Viruses,inline,void
来源: https://www.cnblogs.com/gsn531/p/16512049.html