【upc】 合并果子 | 并查集、树上前缀和

柠檬树上柠檬果,柠檬树下我和我
Re-see特别喜欢柠檬。
Re-see一共采了n个柠檬。一开始每个柠檬自成一堆。之后她又做了Q次操作
1 x y:Re-see觉得不够酸爽,决定把第x个柠檬和第y个柠檬所在的柠檬堆合并。特别的,如果x,y本来就在一堆里,那么什么也不做
2 a b:Re-see酸了,对第a个柠檬所在的柠檬堆中每个柠檬挤了b毫升柠檬汁喝。Re-see操作完后决定吃柠檬,请你回答此时每个柠檬被挤了多少毫升柠檬汁

输入

第一行2个正整数n,Q
接下来Q行表示操作

输出

输出1行表示每个柠檬被挤了多少毫升柠檬汁,空格隔开

样例输入 Copy

2 3
2 1 1
1 2 1
2 1 3

样例输出 Copy

4 3

提示

第一次操作后柠檬堆为[1][2],答案为[1][0]
第二次操作后柠檬堆为[1,2],答案为[1][0]
第三次操作后柠檬堆为[1,2],答案为[4][3]
【数据范围】
保证1<=x,y,a<=n;1<=b<=100
请使用较快的输入输出方式


题目大意:

中文题意

题目思路:

题目涉及到合并,很容易想到用并查集

可是合并过程中,再次对一个根进行修改操作,可能造成权值重复

所以来考虑一下并查集的本质——有根树

所以就可以想到利用树上前缀和是不是就可以表示每个节点的修改的值了?

假设合并两个节点x、y,父节点分别为dx、dy

那么此时合并 pre[dx] = dy

意味着最后遍历需要从dy - >dx ,以后对这个集合的操作都对dy进行操作即可,但是此时会有个问题,对dy操作之后,求前缀和时会把dy的之前的权值加到dx中,但我们需要的并不是这个权值,而是合并之后所加的权值。所以说需要去掉这一部分,去掉这一部分的方法也很简单:c[dx] -= c[dy],此时求前缀和时就会把dy的贡献给去掉了。

复杂度:O(n)

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pp;
const ll INF=1e17;
const int Maxn=2e7+10;
const int maxn =1e6+10;
const int mod=998244353;
const int Mod = 1e9+7;
///const double eps=1e-10;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p,S,T;
vector<int>v[maxn];
int r[maxn],in[maxn];
ll c[maxn],res[maxn];
int pre[maxn];
int Find(int x){
    return x == pre[x]?x:Find(pre[x]);
}
void Merge(int x,int y){
    int dx=Find(x),dy=Find(y);
    if(dx==dy) return;
    if(r[dx]>r[dy]){
        v[dx].push_back(dy);
        pre[dy]=dx;
        c[dy]-=c[dx];
        in[dy]++;
    }
    else if(r[dy]>r[dx]){
        v[dy].push_back(dx);
        in[dx]++;
        pre[dx]=dy;
        c[dx]-=c[dy];
    }
    else{
        v[dy].push_back(dx);
        in[dx]++;
        pre[dx]=dy;
        r[dy]++;
        c[dx]-=c[dy];
    }
}
void dfs(int u,ll w){
    ll temp = w + c[u];
    res[u] = temp;
    for(int e:v[u]) dfs(e,w+c[u]);
}
int main(){
    read(n);read(m);
    for(int i=1;i<=n;i++) pre[i] = i;
    for(int i=1;i<=m;i++){
        ll op,x,y;read(op);read(x);read(y);
        if(op == 1) Merge(x,y);
        else{
            int dx = Find(x);
            c[dx] += y;
        }
    }
    for(int i=1;i<=n;i++){
        if(!in[i]) dfs(i,0);
    }
    for(int i=1;i<=n;i++) printf("%lld ",res[i]);
    return 0;
}
/**
2 10
3 11
 
4 100
5 101
**/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/107517373
UPC