F. 1-1-1, Free Tree!

链接

题目链接

思路

思路参考一个博客。

原来的思路就是更新对应节点的所有邻接值,然后统一更新。但是复杂度\(O(nq)\)

注意到:对树每一个节点,仅有一个父节点,那么考虑修改v节点:每次判断其与父节点的路径是否取到;接着对所有子节点进行统一判断,采用map统一管理子节点的值。修改好ans后,只需要修改对应父节点的map和a数组的值。

注意刚开始的\(dfs\)要写成\(dfs(1,0)\),这样不会影响答案。

代码

#define _CRT_SECURE_NO_WARNINGS 

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define tin long long
#define itn long long
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
const int N = 2e5 + 10;
int a[N];
struct edge
{
    int to, val;
    edge(int to, int val) {
        this->to = to;
        this->val = val;
          
    }
    edge(){}
};
vector<edge>G[N];
itn fa[N];
int sum[N];
bool vis[N];
int n, q;
int ans;
itn tofaval[N];
map<itn, int>points[N];
void dfs(int now,int father) {
    vis[now] = true;
    fa[now] = father;
    for (edge nex : G[now]) {
        itn toer = nex.to, valer = nex.val;
        if(toer == father)tofaval[now] = valer;
        if (vis[toer])continue;
        sum[now] += valer;
        if (a[now] != a[toer]) { ans += valer; }
        points[now][a[toer]] += valer;
        dfs(toer, now);
    }
}


void solve() {
    cin >> n >> q;
    ans = 0;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        vis[i] = 0;
        sum[i] = 0;
        G[i].clear();
        points[i].clear();
    }
    for (int i = 1; i < n; i++) {
        int u, v, w; cin >> u >> v >> w;
        G[u].push_back(edge(v, w));
        G[v].push_back(edge(u, w));

    }
    dfs(1, 0);
    for (int i = 0; i < q; i++) {
        itn v, x; cin >> v >> x;
        ans -= (a[fa[v]] != a[v]) ? tofaval[v] : 0;
        ans += (a[fa[v]] != x) ? tofaval[v] : 0;
        ans -= sum[v] - points[v][a[v]];
        ans += sum[v] - points[v][x];
        points[fa[v]][a[v]] -= tofaval[v];
        points[fa[v]][x] += tofaval[v];
        a[v] = x;
        cout << ans << '\n';
    }
}

signed main() {
    IOS;
    /**/int t;
    cin >> t;
    if(t>0)
    while (t--)
        solve();
    
    return 0;
}
posted @ 2025-08-04 19:30  WHUStar  阅读(10)  评论(0)    收藏  举报