hdu 4858 项目管理(图的分治)
来源:互联网 发布:windows 机顶盒 编辑:程序博客网 时间:2024/04/30 06:54
项目管理
两个节点间可能有多条边,不过一条边的两端必然是不同的节点。
每个节点都有一个能量值。
现在我们要编写一个项目管理软件,这个软件呢有两个操作:
1.给某个项目的能量值加上一个特定值。
2.询问跟一个项目相邻的项目的能量值之和。(如果有多条边就算多次,比如a和b有2条边,那么询问a的时候b的权值算2次)。
然后对于每个测试数据,第一行有两个整数n(1 <= n <= 100000)和m(1 <= m <= n + 10),分别表示点数和边数。
然后m行,每行两个数a和b,表示a和b之间有一条边。
然后一个整数Q。
然后Q行,每行第一个数cmd表示操作类型。如果cmd为0,那么接下来两个数u v表示给项目u的能量值加上v(0 <= v <= 100)。
如果cmd为1,那么接下来一个数u表示询问u相邻的项目的能量值之和。
所有点从1到n标号。
13 21 21 360 1 150 3 41 11 30 2 331 2
41515
共有m条边 设k=sqrt(m) 若一个点的度(即与之有边连接点的个数)小于k成为轻点,剩下的(大于等于k)称为重点
对点i来说degree[i]记录点的度
重点的个数 <=2*m/sqrt(m)=2*sqrt(m)
对于一个点i,A[i]记录这个点的值
对于重点i,sum[i]记录其答案,
对于轻点i,sum[i]无任何作用,轻点的答案通过对所有与轻点相连的点的值求和直接得到
题目可分为三个过程
1.构造图
对点i来说
如果i点是轻点,则记录所有与他相连的点到point[i]中
如果i点是重点,则记录所有与他相连的重点到point[i]中
2.更新图
对点i来说
如果i点是轻点,则更新point[i]中所有重点,即为更新所有与之相连的重点的sum值
如果i点是重点,则更新point[i]中所有点,也即为更新所有与之相连的重点的sum值
3.查询点
对点i来说
如果i点是轻点,则累加所有与之相连的点的值直接求出解
如果i点是重点,则直接输出sum[i],因为sum[i]的值已经更新过了(与重点相连的点有两种——轻点与重点,在2.更新图过程中都完成了更新)
稍微计算一下,就能发现此种方法在点多且密集的情况下,比基础方法快了很多
设轻点个数为N轻,重点个数为N重,轻点所相连点的个数为SIZE轻,重点所相连的个数为SIZE重,重点所相连的重点个数为SIZE重重(重点的个数 <=2*m/sqrt(m)=2*sqrt(m)=2*k=2*SIZE轻)
忽略N轻与N重
故比较SIZE重与SIZE轻+SIZE重重(SIZE重重<=2*k约等于2*SIZE轻)
左式=m 右式=3*sqrt(m)
在点多且边密集的图中,显然改进方法的速度有了很大的提升
#include<cmath>#include<cstdio>#include<cstring>#include<vector>using namespace std;const int MAX=100105;struct node{ int u,v;}edge[MAX];;int k;vector<int>point[MAX];int A[MAX],sum[MAX],degree[MAX];void update(int x,int d){ int i; A[x]+=d; for(i=0;i<point[x].size();i++) if(degree[point[x][i]]>=k) sum[point[x][i]]+=d;}int query(int x){ if(degree[x]<k) { int ans=0; for(int i=0;i<point[x].size();i++) ans+=A[point[x][i]]; return ans; } else return sum[x];}int main(){ int T,n,m,i,u,v,Q,cmd,a,b; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); memset(A,0,sizeof(A)); memset(degree,0,sizeof(degree)); memset(sum,0,sizeof(sum)); for(i=1;i<=n;i++) point[i].clear(); for(i=1;i<=m;i++) { scanf("%d%d",&edge[i].u,&edge[i].v); degree[edge[i].u]++; degree[edge[i].v]++; } k=sqrt(m); for(i=1;i<=m;i++) { u=edge[i].u; v=edge[i].v; if(degree[u]<k) point[u].push_back(v); else if(degree[v]>=k) point[u].push_back(v); if(degree[v]<k) point[v].push_back(u); else if(degree[u]>=k) point[v].push_back(u); } scanf("%d",&Q); while(Q--) { scanf("%d",&cmd); if(cmd==0) { scanf("%d%d",&a,&b); update(a,b); } else { scanf("%d",&a); printf("%d\n",query(a)); } } } return 0;}
对点i来说,如果一个点是轻点,则记录所有与他相连的点到point[i]中
如果一个点是重点,则记录所有与他相连的重点到point[i]中
- hdu 4858 项目管理(图的分治)
- 【HDU 4858】 项目管理 【图的分治】
- hdu 4858 项目管理 (图的分治)
- hdu 4858 项目管理(图的分治)
- hdu 4858 项目管理 图分治 (复合算法)
- HDU 4858 项目管理
- hdu 4858 项目管理
- HDU 4858 项目管理
- HDU 4858 项目管理
- hdu 4858 项目管理
- hdu 4858 项目管理
- hdu 4858 项目管理
- HDU 4858 项目管理
- HDU 4858 项目管理(模拟)
- HDU-4858-项目管理【STL】
- [hdu 4858项目管理]分块
- hdu 4858 项目管理 分块
- HDU 4858 项目管理 (简单图+暴力)
- HDU-5610 Array(枚举)
- 2016年英语学习——1月
- java中常用的字符串的截取方法
- 3Sum Closest题解
- 找出升序数组中和为给定值的两个数字 不要直接用形参里的表示,输出或清零输入时都是大忌
- hdu 4858 项目管理(图的分治)
- 自定义Mina中的拦截器
- 华夏神农实习总结
- sync 接口返回的内容
- 【安卓开发】JNI常用接口 - 2
- eclipse luna 集成weblogic
- 程序人生名言
- 可重入和线程安全
- 开源协议