首页 > 其他分享 >PANDORA PARADOXXX

PANDORA PARADOXXX

时间:2024-09-09 21:14:58浏览次数:8  
标签:PARADOXXX fu fv int nd fa PANDORA find

PANDORA PARADOXXX

题意

给出一棵树,每次操作删除树上的一条边,询问树上所有连通块中直径的最大值。

思路

倒序操作,删边变为连边。

预处理出做完所有操作后的答案。

使用并查集维护连通性,记录每个连通块内直径的端点。

合并两个集合时,新的直径端点只可能是原来两个集合四个端点中的两个。

使用 LCA 求树上距离,枚举 \(6\) 种情况, 取最大即可。

最后正序输出答案。

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
typedef long long ll;
template <typename T> void qr(T& x) {
	x = 0; T f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {if (ch == '-') f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - 48;ch = getchar();}
    x *= f;
}
template <typename T> void qf(T x) {
	if (x < 0) putchar('-'), x = -x;
	if (x >= 10) qf(x / 10);
	putchar(x % 10 + 48);
}
int T, tot, ver[N << 1], nxt[N << 1], head[N];
int n, Q, u[N], v[N], q[N], fa[N][25], de[N];
ll d[N], w[N], edge[N], D[N], ans[N];
int f[N], P[N][2], mx, mxp;
bool qed[N], vis[N];
vector <pair<int,ll> > e[N];
void add(int x, int y, ll z) {
    ver[++ tot] = y;
    nxt[tot] = head[x];
    head[x] = tot;
    edge[tot] = z;
}
int find(int x) {return f[x] == x ? x : f[x] = find(f[x]);}
void link(int x, int y) {
    int fx = find(x), fy = find(y);
    if (fx == fy) return ;
    f[fx] = fy;
}
void init(int x) {
    de[x] = de[fa[x][0]] + 1;
    for (int i = 1; i < 25; i ++) 
        fa[x][i] = fa[fa[x][i - 1]][i - 1];
    for (int i = head[x], y; i; i = nxt[i]) {
        y = ver[i];
        if (y == fa[x][0]) continue;
        fa[y][0] = x, d[y] = d[x] + edge[i];
        init(y);
    }
} 
int LCA(int x, int y) {
    if (de[x] < de[y]) swap(x, y);
    for (int i = 24; i >= 0; i --) 
        if (de[fa[x][i]] >= de[y]) x = fa[x][i];
    if (x == y) return x;
    for (int i = 24; i >= 0; i --)
        if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
    return fa[x][0];
}
ll dis(int x, int y) {return d[x] + d[y] - (d[LCA(x, y)] << 1);}
void dfs(int x) {
    if (D[x] > mx) mx = D[x], mxp = x;
    for (auto [y,w] : e[x]) {
        if (vis[y]) continue;
        vis[y] = 1, D[y] = D[x] + w;
        dfs(y);
        D[y] = vis[y] = 0;
    }
}
void solve() {
    qr(n), qr(Q);
    for (int i = 1; i < n; i ++) {
        qr(u[i]), qr(v[i]), qr(w[i]);
        add(u[i], v[i], w[i]), add(v[i], u[i], w[i]);
    }
    for (int i = 1; i <= n; i ++) f[i] = i;
    for (int i = 1; i <= Q; i ++) qr(q[i]), qed[q[i]] = 1;
    for (int i = 1; i < n; i ++) {
        if (qed[i]) continue;
        e[u[i]].push_back({v[i],w[i]});
        e[v[i]].push_back({u[i],w[i]});
        link(u[i], v[i]);
    }
    init(1);
    for (int i = 1; i <= n; i ++) {
        if (f[i] == i) {
            mx = -1;
            vis[i] = 1; dfs(i); vis[i] = 0;
            P[i][0] = mxp;
            mx = -1;
            vis[P[i][0]] = 1, dfs(P[i][0]); vis[P[i][0]] = 0;
            P[i][1] = mxp;
            ans[Q] = max(ans[Q], dis(P[i][0], P[i][1]));  
        }
    }
    for (int i = Q, fu, fv, nl, nr; i >= 1; i --) {
        fu = find(u[q[i]]), fv = find(v[q[i]]);
        ll p = dis(P[fu][0], P[fu][1]), nd = -1;
        if (p > nd) nd = p, nl = P[fu][0], nr = P[fu][1];
        p = dis(P[fv][0], P[fv][1]);
        if (p > nd) nd = p, nl = P[fv][0], nr = P[fv][1];
        p = dis(P[fu][0], P[fv][0]);
        if (p > nd) nd = p, nl = P[fu][0], nr = P[fv][0];
        p = dis(P[fu][0], P[fv][1]);
        if (p > nd) nd = p, nl = P[fu][0], nr = P[fv][1];
        p = dis(P[fu][1], P[fv][0]);
        if (p > nd) nd = p, nl = P[fu][1], nr = P[fv][0];
        p = dis(P[fu][1], P[fv][1]);
        if (p > nd) nd = p, nl = P[fu][1], nr = P[fv][1];
        link(u[q[i]], v[q[i]]);
        fu = find(u[q[i]]);
        P[fu][0] = nl, P[fu][1] = nr, ans[i - 1] = max(ans[i], nd);
    }
    for (int i = 1; i <= Q; i ++) qf(ans[i]), putchar('\n');
    for (int i = 1; i <= n; i ++) 
        head[i] = u[i] = v[i] = q[i] = d[i] = w[i] = edge[i] = D[i] = 
        qed[i] = vis[i] = de[i] = P[i][0] = P[i][1] = ans[i] = qed[i] = 0;
    for (int i = 1; i <= n; i ++)
        for (int j = 0; j < 25; j ++) fa[i][j] = 0;
    tot = mx = mxp = 0;
    for (int i = 1; i <= n; i ++) e[i].clear();
}
signed main() {
    qr(T);
    while (T --) solve();
    return 0;
}

标签:PARADOXXX,fu,fv,int,nd,fa,PANDORA,find
From: https://www.cnblogs.com/maniubi/p/18405345

相关文章

  • P10238 [yLCPC2024] F. PANDORA PARADOXXX
    这里主要是了解一下套路,首先说一下树的直径的性质。1.任何一个点到它所在的联通块中距离最远的点一定是树的直径两点之一。2.两个连通块合并以后,新的树的直径一定为原先两个连通块中树的直径中的两个。了解完这个,我们来看这道题,根据树的直径的性质,我们可以来维护连通块,那一个......
  • P10238 [yLCPC2024] F. PANDORA PARADOXXX 题解
    题目传送门前置知识树链剖分|树的直径|最近公共祖先|并查集解法正着删边不太可做,考虑离线下来反着加边。一个显而易见的结论:设点集\(A\)的直径的两个端点为\(u_{1},v_{1}\),另一个点集\(B\)的直径的两个端点为\(u_{2},v_{2}\),则\(A\bigcupB\)的直径端点一定是......
  • P10238 [yLCPC2024] F. PANDORA PARADOXXX
    P10238[yLCPC2024]F.PANDORAPARADOXXX并查集维护连通性+结论+数据结构维护距离题目的操作是删边通常复杂,并且不强制在线,所以离线倒过来加边。题目要求的就是当前所有连通块的直径的最大值,考虑加边后两个连通块合并后直径的变化。有结论:合并后的连通块的直径两端点一定是合......
  • P10238 [yLCPC2024] F. PANDORA PARADOXXX 题解
    分析考虑时光倒流。对于需要合并的两个连通块\(x,y\),其合并之后的最远点对距离一定是合并之前的两组点对中产生的。在合并的时候枚举点对,取距离最大值即可。由于我们是倒着来的,所有连通块的最远点对距离最大值不减,所以能直接在合并之后取最大值。维护连通块用并查集即可。复杂......
  • ChatGPTGPT本地一键登录,无需魔法即开即用:PandoraNext重磅归来,支持chatgpt所有最新功
    PandoraNext简单介绍PandoraCloud+PandoraServer+SharedChat+BackendAPIProxy= PandoraNext支持GPTs,最新UI。支持多种登录方式:(相当于PandoraCloud)账号/密码AccessTokenSessionTokenRefreshTokenShareToken可内置tokens(可使用上述所有Token),支持设置密码。(相当于Pan......
  • Spring——Alibaba-pandora boot实战
    摘要阿里的PandoraBoot的核心是Pandora,因此在介绍PandoraBoot之前需要先介绍Pandora。在阿里集体内部,几乎所有的应用都用到了各式各样的中间件,比如HSF、TDDL、Diamond等等。本身中间件之间可能就有版本依赖的问题,比如你的应用HSF和Diamond分别依赖了同名jar包的不同版本,maven只会......
  • HDU 3695 Computer Virus on Planet Pandora
    ProblemDescription    AliensonplanetPandoraalsowritecomputerprogramslikeus.Theirprogramsonlyconsistofcapitalletters(‘A’to‘Z’......