1. 程式人生 > 其它 >[Acwing藍橋杯DP] 2069. 網路分析

[Acwing藍橋杯DP] 2069. 網路分析

題目連結:2069. 網路分析 - AcWing題庫

題目描述:
給出一個 n 個孤立點的圖,每個點上的權值都是 0,進行 m 次操作
操作 1 :把兩個點所在的連通塊合併起來
操作 2 :向某個點所在的連通塊的所有點累加一個值
最後輸出每個點上的權值

資料範圍:1<=n<=1e4

                  1<=m<=1e5

分析:複雜並查集 樹上差分
這個題不但要將點連起來,還要求每個點上的權值;

注意:每次操作是有先後順序的,如果以前都已經連在一塊了,再次連入時候,不加原來的值

難點:1、每個點的權值為該點到根節點的路徑上權值的和距離

           2、優化路徑 d[x]+=d[p[x]] ;

    int r=find(p[x]);//這一步呼叫的find函式返回後別忘了執行後面的語句
    d[x]+=d[p[x]];//看不懂就根據手動模擬一下樣例
    p[x]=r;//直接賦值p[x]=根節點,下次再想找x的父節點就不用花大量時間遍歷了,p數組裡存的就是

           3、將一個樹A與另一個樹B合併

          將A接在B後邊 要將A的根結點的權值減去B的根結點權值,避免重複計算,防止1的定義錯亂

程式碼如下:

#include <bits/stdc++.h>

using namespace std;

const int N=1e4+10;

int n,m; int p[N],d[N]; int find(int x) { if(x==p[x]||p[p[x]]==p[x])return p[x]; int r=find(p[x]); d[x]+=d[p[x]]; p[x]=r; return r; } int main() { cin>>n>>m; for(int i=1;i<=n;i++)p[i]=i; while(m--) { int t,a,b; scanf("%d%d%d",&t,&a,&b);
if(t==1) { a=find(a),b=find(b); if(a!=b) { d[a]-=d[b]; p[a]=b; } }else { a=find(a); d[a]+=b; } } for(int i=1;i<=n;i++) { if(find(i)==i)printf("%d ",d[i]); else printf("%d ",d[i]+d[p[i]]); } return 0; }

 

END!!!