【传智杯】第三届“传智杯”全国大学生IT技能大赛(初赛A组)G - 森林 | 并查集、思维

题目大意:

清蒸鱼是一个尽职尽责的 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 newvallastval就可以了
所以考虑把操作离线储存后,倒叙处理(减边换为加边)
对于权值的变化 也对应取反就好了
注意倒叙处理前,应该要保存操作完之后图的权值分块情况,之后在此图上进行操作,而不是直接 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
****/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/111680368