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 }
沉迷于日日菜醒,不能自拔
posted on 2017-08-17 10:00 仰望咸鱼Orzzzz 阅读(128) 评论(0) 编辑 收藏 举报