[hdu 4858项目管理]分块
知识点:graph
分块
1. 题目链接
2. 题意描述
有
n
个顶点
- 操作一:将所有与
- 操作二:查询顶点
数据范围: (1<=n<=100000,1<=m<=n+10,0<=v<=100)
3. 解题思路
分块的一道比较好的题目呐。首先,观察题目,给定的是一个明显的稀疏图。边数为
m
,那么所有顶点度数之和是
那么,显然:不会超过有
2∗m−−−−−√
个顶点的度数大于
2∗m−−−−−√
。
那么我们可以以
2∗m−−−−−√
为分界值进行分块了。
- 对于所有度数小于
2∗m−−−−−√
的顶点,我们直接将权值累加到与
u
相连的顶点中去;
- 对于所有度数大于等于
那么查询的时候,就是两部分贡献之和。这样,就可以将复杂度控制在 O(q∗2∗m−−−−−√)
4. 实现代码
#include <bits/stdc++.h>
using namespace std;
typedef __int64 LL;
typedef long double LB;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
const LB eps = 1e-8;
const int MAXN = 100000 + 15;
struct Edge {
int v, next;
} edge[MAXN << 1];
int head[MAXN], tot;
int n, m, q, du[MAXN];
LL tag[MAXN], ans[MAXN];
vector<int> G[MAXN];
inline void add_edge(int& u, int& v) {
edge[tot] = Edge{v, head[u]};
head[u] = tot ++;
}
void init() {
tot = 0;
memset(head, -1, sizeof(head));
memset(du, 0, sizeof(du));
memset(tag, 0, sizeof(tag));
memset(ans, 0, sizeof(ans));
for(int i = 1; i <= n; ++i) G[i].clear();
}
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
int _, base, cmd, u, v; scanf("%d", &_);
while(_ --) {
scanf("%d %d", &n, &m);
init();
for(int x = 0; x < m; ++x) {
scanf("%d %d", &u, &v);
add_edge(u, v); add_edge(v, u);
du[u] ++, du[v] ++;
}
base = sqrt(2 * m);
for(int x = 1; x <= n; ++x) {
if(du[x] < base) continue;
for(int i = head[x]; ~i; i = edge[i].next) G[edge[i].v].push_back(x);
}
scanf("%d", &q);
while(q --) {
scanf("%d", &cmd);
if(cmd == 0) {
scanf("%d %d", &u, &v);
if(du[u] >= base) { tag[u] += v; continue; }
for(int i = head[u]; ~i; i = edge[i].next) ans[edge[i].v] += v;
} else {
scanf("%d", &u);
LL ans2 = 0;
for(int i = 0, sz = G[u].size(); i < sz; ++i) ans2 += tag[G[u][i]];
printf("%I64d\n", ans[u] + ans2);
}
}
}
return 0;
}