【HDU 4858】 项目管理 【图的分治】

题解:

共有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轻)

 【HDU 4858】 项目管理 【图的分治】_第1张图片

 忽略N轻与N重 

 

故比较SIZE重与SIZE轻+SIZE重重(SIZE重重<=2*k约等于2*SIZE轻)

              左式=m             右式=3*sqrt(m)

在点多且边密集的图中,显然改进方法的速度有了很大的提升

#include  
#include  
#include  
#include  
using namespace std;  
const int MAX=100105;  
struct node  
{  
    int u,v;  
}edge[MAX];;  
int k;  
vectorpoint[MAX];  
int A[MAX],sum[MAX],degree[MAX];  
void update(int x,int d)  
{  
    int i;  
    A[x]+=d;  
    for(i=0;i=k)  
            sum[point[x][i]]+=d;  
}  
int query(int x)  
{  
    if(degree[x]=k)  
                point[u].push_back(v);  
            if(degree[v]=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]中


你可能感兴趣的:(ACM)