HDU 4858 项目管理

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4858

题意:

  给一张图(稀疏图)且图上可能有重边,每个点都有一个value且初始都为0,有两个操作1、使某个点的value加上一个值;2、求一个点所连的所有边的另一个端点的value和,如果有重边则计算多次。

题解:

  通过分块的思想,把图上的点按连边的多少(是否小于sqrt(m))分成重点和轻点。将所有轻点完全建边,重点只建与重点之间的边。每次更新点的value时更新所有连接的边的sum因为每个点连的边不超过sqrt(m)所以更新的复杂度是sqrt(m),询问时对于轻点,暴力计算与它连的点的value和,复杂度为sqrt(m),对于重点只需返回该点的sum即可。

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=100000+200;
 4 vector<int> g[maxn];
 5 struct Edge {
 6     int u,v;
 7 }e[maxn*2];
 8 int T,Q,n,m,u,unit,v,op,ranks[maxn],sum[maxn],a[maxn];
 9 
10 void update(int x, int d) {
11     a[x]+=d;
12     for(auto i:g[x]) sum[i]+=d;
13 }
14 int query(int x) {
15     if(ranks[x]<unit) {
16         sum[x]=0;
17         for(auto i:g[x]) sum[x]+=a[i];
18         return sum[x];
19     }
20     else return sum[x];
21 }
22 int main() {
23     scanf("%d",&T);
24     while(T--) {
25         scanf("%d%d",&n,&m);
26         memset(sum,0,sizeof(sum));
27         memset(a,0,sizeof(a)); 
28         memset(ranks,0,sizeof(ranks));
29         for(int i=1;i<=m;++i) {
30             scanf("%d%d",&e[i].u,&e[i].v);
31             ranks[e[i].u]++;
32             ranks[e[i].v]++;
33         }
34         unit=sqrt(m+0.5);
35         for(int i=1;i<=m;++i) {
36             u=e[i].u; v=e[i].v;
37             if(ranks[u]<unit) g[u].push_back(v);
38             else if(ranks[v]>=unit) g[u].push_back(v);
39             if(ranks[v]<unit) g[v].push_back(u);
40             else if(ranks[u]>=unit) g[v].push_back(u);
41         }
42         scanf("%d",&Q);
43         while(Q--) {
44             scanf("%d%d",&op,&u);
45             if(op) printf("%d\n",query(u));
46             else {
47                 scanf("%d",&v); update(u,v);
48             }
49         }
50         for(int i=1;i<=n;++i) g[i].clear();
51     }
52     return 0;
53 }
View Code

 

posted on 2017-08-17 10:00  仰望咸鱼Orzzzz  阅读(128)  评论(0编辑  收藏  举报

导航