分块法 hdu4858 项目管理

来源:互联网 发布:云计算公司排名 编辑:程序博客网 时间:2024/06/05 06:39

一看到这题,首先会觉得非常像单点更新的线段树,但是却不怎么好操作

然后应该往分块的方向去想


因为只有m条边,所以所有点的度总和是2m,那么设度数>=sqrt(m)的点叫做重点,反之则是轻点

那么重点的个数<=2m/sqrt(m)=2sqrt(m)

设A[i]表示该点的值,sum[i]表示该点周围相连的点的A[i]之和


构造图的时候也有技巧,对于一条边(u,v)

如果u是轻点,直接添加(u,v)这条边  //因为边数不会超过sqrt(m)条

如果u是重点,那么v也是重点时候,才添加(u,v)这条边 //因为重点个数小于2sqrt(m),所以这里添加的边也不算特别多


更新时

对于每个点,先更新自己,A[u]+=d,遍历其所有的边,使sum[v]+=d

实际上本来如果v是轻点,是可以不用操作的,但是也无所谓啦,反正只有u也是轻点的时候,v才可能是轻点,但是u的边数已经很小了,加不加判断都无所谓

操作了也并不会影响答案,因为如果i是轻点,sum[i]是没用的,等下继续讲


查询时

如果x是重点,由之前的构图和更新能知道,对于任意v是重点边,都是添加在图里面的,所以sum[x]就是答案

如果x是轻点,实际上sum[x]是没意义的,但是与x连接的边数<=sqrt(m),所以直接枚举所有周围的点,积累周围点的A值即可


#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<vector>#include<algorithm>using namespace std;typedef long long LL;const int mod=1e9+7;const int MX=100100+5;const int INF=0x3f3f3f3f;struct Edge{    int u,v;}E[MX];int n,m,unit,Q;int P[MX],sum[MX],A[MX];vector<int>G[MX];void update(int x,int d){    A[x]+=d;    for(int i=0;i<G[x].size();i++){        int nxt=G[x][i];        sum[nxt]+=d;    }}int query(int x){    if(P[x]<unit){        sum[x]=0;        for(int i=0;i<G[x].size();i++){            int nxt=G[x][i];            sum[x]+=A[nxt];        }        return sum[x];    }else{        return sum[x];    }}int main(){    int T;    scanf("%d",&T);    while(T--){        scanf("%d%d",&n,&m);        memset(A,0,sizeof(A));        memset(P,0,sizeof(P));        memset(sum,0,sizeof(sum));        for(int i=1;i<=n;i++) G[i].clear();        for(int i=1;i<=m;i++){            scanf("%d%d",&E[i].u,&E[i].v);            P[E[i].u]++;            P[E[i].v]++;        }        unit=sqrt(m+0.5);        for(int i=1;i<=m;i++){            int u=E[i].u,v=E[i].v;            if(P[u]<unit) G[u].push_back(v);            else if(P[v]>=unit) G[u].push_back(v);            if(P[v]<unit) G[v].push_back(u);            else if(P[u]>=unit) G[v].push_back(u);        }        scanf("%d",&Q);        while(Q--){            int cmd,a,b;            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;}


0 0