题目大意:
清蒸鱼是一个尽职尽责的 YYH Land 护林者。他负责每天维护 YYH Land 的森林。在最开始的时候,YYH Land 只有一棵具有 n n n 个节点的树,每个节点有一个灵力值 v v v。
由于 YYH Land 是一片神奇的国度,YYH Land 的树也有一些神奇的能力,具体来说它满足如下操作:
- 1 e
编号为 e e e 的边突然消失,使得它所在的那棵树变成了两棵树。
- 2 u u u v a l val val
编号为 uu 的节点的灵力值变成了 valval。
- 3 u u u
清蒸鱼进行了一次查询,查询 uu 所在的那棵树的灵力值之和。
现在你需要帮助清蒸鱼,来模拟上述事件,以了解森林的变迁。
题目思路:
看到加边、减边的操作,向并查集
上靠拢就可以了
由于这题只限于删边,并且伴随着权值改变
显然,删边操作是不好维护灵力值的
但是,加边操作对于每一块的灵力值的改变,是非常好维护的
假设只有加边操作,那么对于一个点x的灵力值发生变化,那么就有点x的的根(并查集寻根)增加 n e w v a l − l a s t v a l newval - lastval newval−lastval就可以了
所以考虑把操作离线储存后,倒叙处理(减边换为加边)
对于权值的变化 也对应取反就好了
注意倒叙处理前,应该要保存操作完之后图的权值
及分块
情况,之后在此图上进行操作,而不是直接 n n n个点上进行操作
Code:
/*** keep hungry and calm CoolGuang! ***/
/*#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)*/
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17;
const ll maxn = 4e5+700;
const int mod= 1e9+7;
const int up = 1e9;
template<typename T>inline void read(T &a){
char c=getchar();T x=0,f=1;while(!isdigit(c)){
if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
int pre[maxn];
ll num[maxn],val[maxn];
pair<int,int>e[maxn];
vector<int>v[maxn];
int vis[maxn];
int Find(int x){
return pre[x]==x?x:pre[x] = Find(pre[x]);
}
struct node{
int op,x,y;
}q[maxn];
ll res[maxn];
int main(){
read(n);read(m);
for(int i=1;i<=n;i++){
read(num[i]);
val[i] = num[i];
pre[i] = i;
v[i].push_back(num[i]);
}
for(int i=1;i<=n-1;i++){
int x,y;read(x);read(y);
e[i] = {
x,y};
}
for(int i=1;i<=m;i++){
read(q[i].op);
if(q[i].op == 1){
read(q[i].x);
vis[q[i].x] = 1;
}
else if(q[i].op == 2){
read(q[i].x);
read(q[i].y);
v[q[i].x].push_back(q[i].y);
}else read(q[i].x);
}
for(int i=1;i<=n;i++)
if(v[i].size())
val[i] = num[i] = v[i].back();
for(int i=1;i<=n-1;i++){
if(vis[i]) continue;
int dx = Find(e[i].first),dy = Find(e[i].second);
if(dx != dy){
pre[dx] = dy;
val[dy] += val[dx];
}
}
for(int i=m;i>=1;i--){
if(q[i].op == 1){
int dx = Find(e[q[i].x].first),dy = Find(e[q[i].x].second);
if(dx != dy){
pre[dx] = dy;
val[dy] += val[dx];
}
}else if(q[i].op == 2){
v[q[i].x].pop_back();
int dx = Find(q[i].x);
val[dx] += v[q[i].x].back() - num[q[i].x];
num[q[i].x] = v[q[i].x].back();
}
else res[i] = val[Find(q[i].x)];
}
for(int i=1;i<=m;i++){
if(res[i])
printf("%lld\n",res[i]);
}
return 0;
}
/***
5 7
1 2 3 4 5
1 2
2 3
3 4
4 5
3 1
3 2
2 1 5
1 2
2 1 3
3 1
3 5
****/