题目描述
思路
因为更改点的权值不会改变树的结构,但是删去一条边会改变树的结构,不同与增加一条边,删除一条边的处理是很麻烦(没实现过!!!)
既然我们无法删除一条边,那么我们可以倒着加边!
这类问题的通用解法是:先保存删边,然后倒叙处理。
犯的错误
1.题目中给定的边的下标从 \(1\) 开始(题目中说的是第 \(k\) 条边,那么 \(k\) 肯定从 \(1\) 开始了),但我代码中边的下标从 \(0\) 开始。不仔细读题的后果)
2.关于节点权值的修改,我们需要一个额外的数组 \(sum\) 来统计树的权值,如果直接在 \(w\) 上修改的话,考虑 \(idx\) 是某个树的 \(root\)(体现在代码中就是并查集的根),如果我们直接修改 \(w[idx]\) ,因为我们的的本意只是修改节点的权值,但是我们把整颗树的权值修改了!那就大错特错了!
3.另外就是由于我们是倒着处理,因此需要倒着输出答案。(倒序处理基本都是需要倒着数处答案的吧!)
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int w[N], pre[N], sum[N];
bool st[N];
vector<pair<int,int>> add;
stack<pair<int,pair<int,int>>> query;
stack<int> res;
int find(int x)
{
if(pre[x] == x) return pre[x];
return pre[x] = find(pre[x]);
}
void read_init()
{
for(int i = 0; i < N; i ++ ) pre[i] = i;
cin >> n >> m;
for(int i = 1; i <= n; i ++ ) cin >> w[i], sum[i] = w[i];
for(int i = 0; i < n - 1; i ++ ) {
int a, b; cin >> a >> b;
add.push_back({a,b});
}
}
void read_query()
{
for(int i = 0; i < m; i ++ ) {
int op, a, b;
cin >> op >> a;
if(op == 1) { // delete edge
query.push({1,{a,0}});
st[a] = true;
}
else if(op == 2) { // change edge weight
cin >> b;
query.push({2,{a,w[a]}});
int fa = find(a);
sum[fa] += b - w[a];
w[a] = b;
}
else { // query weight of tree
query.push({3,{a,0}});
}
}
}
void add_edge()
{
for(int i = 0; i < n - 1; i ++ ) {
if(!st[i + 1]) {
int a = add[i].first, b = add[i].second;
int fa = find(a), fb = find(b);
if(fa != fb) {
pre[fa] = fb;
sum[fb] += sum[fa];
}
}
}
}
void solve()
{
while(query.size()) {
auto it = query.top(); query.pop();
int op = it.first, a = it.second.first, b = it.second.second;
if(op == 1) { // delete edge
// now add edge
int idx = a - 1;
a = add[idx].first, b = add[idx].second;
// cout << "a-b: " << a << ' ' << b << endl;
int fa = find(a), fb = find(b);
if(fa != fb) {
pre[fa] = fb;
sum[fb] += sum[fa];
}
}
else if(op == 2) { // change edge weight
int fa = find(a);
sum[fa] += b - w[a];
w[a] = b;
}
else { // query weight of tree
res.push(sum[find(a)]);
}
}
while(res.size()) {
cout << res.top() << endl;
res.pop();
}
}
int main()
{
read_init();
read_query();
add_edge();
solve();
}
标签:pre,落谷,int,sum,离线,fa,add,query,倒序
From: https://www.cnblogs.com/ALaterStart/p/16906885.html