[Acwing藍橋杯DP] 2069. 網路分析
阿新 • • 發佈:2022-04-05
題目描述:
給出一個 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!!!