zoukankan      html  css  js  c++  java
  • 洛谷 P3320: bzoj 3991: LOJ 2182: [SDOI2015]寻宝游戏

    题目传送门:LOJ #2182

    题意简述:

    一棵 (n) 个节点的树,边有边权。

    每个点可能是关键点,每次操作改变一个点是否是关键点。

    求所有关键点形成的极小联通子树的边权和的两倍。

    题解:

    有一个结论:DFS 序求出后,假设关键点按照 DFS 序排序后是 ({a_1,a_2,ldots ,a_k})

    那么所有关键点形成的极小联通子树的边权和的两倍等于 (mathrm{dist}(a_1,a_2)+mathrm{dist}(a_2,a_3)+cdots+mathrm{dist}(a_{k-1},a_k)+mathrm{dist}(a_k,a_1))

    画个图感性理解一下,应该是很好懂的。

    那么求一下 DFS 序,每次操作相当于往集合里加入/删除一个元素。

    假设插入 (x),它DFS序左右两边分别是 (y)(z)。那么答案加上 (mathrm{dist}(x,y)+mathrm{dist}(x,z)-mathrm{dist}(y,z)) 即可。

    删除同理。还有,求 LCA 就用个倍增或者树剖吧,Tarjan 离线比较麻烦。

    用 STL 自带的 set 容器维护起来很方便。你也可以手写树状数组/线段树/平衡树。

    #include <cstdio>
    #include <set>
    
    typedef long long LL;
    const int MN = 100005;
    
    int N, M;
    int h[MN], nxt[MN * 2], to[MN * 2], w[MN * 2], tot;
    inline void ins(int x, int y, int z) {
    	nxt[++tot] = h[x], to[tot] = y, w[tot] = z, h[x] = tot;
    }
    
    int dfn[MN], idf[MN], dfc;
    int dep[MN], faz[MN][17];
    LL dis[MN];
    
    void DFS(int u, int fz) {
    	dfn[u] = ++dfc; idf[dfc] = u; dep[u] = dep[faz[u][0] = fz] + 1;
    	for (int j = 1; 1 << j < dep[u]; ++j) faz[u][j] = faz[faz[u][j - 1]][j - 1];
    	for (int i = h[u]; i; i = nxt[i]) if (to[i] != fz) dis[to[i]] = dis[u] + w[i], DFS(to[i], u);
    }
    
    inline int lca(int x, int y) {
    	if (dep[x] < dep[y]) std::swap(x, y);
    	for (int d = dep[x] - dep[y], j = 0; d; d >>= 1, ++j)
    		if (d & 1) x = faz[x][j];
    	if (x == y) return x;
    	for (int j = 16; ~j; --j) if (faz[x][j] != faz[y][j])
    		x = faz[x][j], y = faz[y][j];
    	return faz[x][0];
    }
    
    inline LL dist(int x, int y) { return dis[x] + dis[y] - 2 * dis[lca(x, y)]; }
    
    bool vis[MN];
    std::set<int> st;
    std::set<int>::iterator it;
    LL Ans;
    
    int main() {
    	scanf("%d%d", &N, &M);
    	for (int i = 1, x, y, z; i < N; ++i) {
    		scanf("%d%d%d", &x, &y, &z);
    		ins(x, y, z), ins(y, x, z);
    	}
    	DFS(1, 0);
    	for (int m = 1, x, y, z; m <= M; ++m) {
    		scanf("%d", &x);
    		x = dfn[x];
    		if (!vis[idf[x]]) st.insert(x);
    		y = idf[(it = st.lower_bound(x)) == st.begin() ? *--st.end() : *--it];
    		z = idf[(it = st.upper_bound(x)) == st.end() ? *st.begin() : *it];
    		if (vis[idf[x]]) st.erase(x);
    		x = idf[x];
    		LL d = dist(x, y) + dist(x, z) - dist(y, z);
    		if (!vis[x]) vis[x] = 1, Ans += d;
    		else vis[x] = 0, Ans -= d;
    		printf("%lld
    ", Ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    sql2slack alash3al 开源的又个轻量级工具
    pgspider fetchq 扩展docker镜像
    godns 集成coredns 的demo
    godns 简单dnsmasq 的dns 替换方案
    aviary.sh 一个基于bash的分布式配置管理工具
    使用coredns 的template plugin实现一个xip 服务
    nginx 代理 coredns dns 服务
    基于nginx proxy dns server
    几个不错的geodns server
    spring boot rest api 最好添加servlet.context-path
  • 原文地址:https://www.cnblogs.com/PinkRabbit/p/10356940.html
Copyright © 2011-2022 走看看