文章目錄
1. 題目描述
1.1. Limit
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
1.2. Problem Description
我們建造了一個大項目!這個項目有 個節點,用很多邊連接起來,並且這個項目是連通的!
兩個節點間可能有多條邊,不過一條邊的兩端必然是不同的節點。
每個節點都有一個能量值。
現在我們要編寫一個項目管理軟件,這個軟件呢有兩個操作:
- 給某個項目的能量值加上一個特定值。
- 詢問跟一個項目相鄰的項目的能量值之和。(如果有多條邊就算多次,比如 和 有 條邊,那麼詢問 的時候 的權值算 次)。
1.3. Input
第一行一個整數 ,表示測試數據的個數。
然後對於每個測試數據,第一行有兩個整數 和 ,分別表示點數和邊數。
然後 行,每行兩個數 和 ,表示 和 之間有一條邊。
然後一個整數 。
然後 行,每行第一個數 表示操作類型。如果 爲 ,那麼接下來兩個數 表示給項目 的能量值加上 。
如果 爲 ,那麼接下來一個數 表示詢問 相鄰的項目的能量值之和。
所有點從 到 標號。
1.4. Output
對每個詢問,輸出一行表示答案。
1.5. Sample Input
1
3 2
1 2
1 3
6
0 1 15
0 3 4
1 1
1 3
0 2 33
1 2
1.6. Sample Output
4
15
15
1.7. Source
2. 解讀
看到題目中的節點和連邊,我們很自然地會想到用圖去存儲,但是
節點最大數量是 10萬,要存一個10萬x10萬的二維數組非常容易爆內存。而從題目中我們可以發現,這個圖的連邊是比較稀疏的,所以我們可以採用鄰接表的方式進行存儲。
用鄰接表存儲了點和連邊的關係之後,我們再用一個數組去存儲每一個節點的相鄰節點能量之和。在某一個節點能量增加之後,增加所有與其相鄰的節點的能量,有查詢請求時直接輸出即可。
我查了網上的一些其他解讀,據說這裏用到了一種算法叫做分塊算法,感興趣的同學可以瞭解一下。
3. 代碼
#define mill 100010
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
int main()
{
// test case
int t;
scanf("%d", &t);
// Buffer
long long list[mill];
// 聲明鄰接表
vector<int> vec_list[mill];
for (int j = 0; j < t; j++) {
// 清空鄰接表
memset(vec_list, 0, sizeof(vec_list));
// 清空Buffer
memset(list, 0, sizeof(list));
// 讀數據
int n, m;
scanf("%d %d", &n, &m);
// 連邊
int a, b;
// 循環m次,讀入連邊
for (int i = 0; i < m; i++) {
scanf("%d %d", &a, &b);
// ---存入ab-----------
vec_list[a].push_back(b);
// ---存入ba-----------
vec_list[b].push_back(a);
}
// 讀取query
// query個數
int q;
scanf("%d", &q);
// query 類型
int qType;
// query內容
int u, v;
// 讀入query
for (int i = 0; i < q; i++) {
scanf("%d", &qType);
if (qType == 0) {
scanf("%d %d", &u, &v);
// 操作query 0
// 讀連邊
vector<int> vec = vec_list[u];
// 爲每個與u相連的點加v能量
for (unsigned long k = 0; k < vec.size(); k++) {
list[vec[k]] += v;
}
} else {
scanf("%d", &u);
// 操作query 1
printf("%lld\n", list[u]);
}
}
}
}