HDU 4858 项目管理 分块
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4858
题解:
下面说一个插入查询时间复杂度为sqrt(m)的算法:
对每个点定义两个值:val,sum,val记录自己的特征值,sum记录周边所有点特征值的和。
现在我们把所有的节点分成两类,重点(度数>=sqrt(m)),轻点(度数sqrt(m))。
插入:
轻点更新自己的val,同时更新所有的邻点的sum值
重点更新自己的val,同时只更新相邻重点的sum值(所以重点不需要连边到轻点)
查询:
轻点:暴力周边的所有邻点的val值。
重点:直接输出自己的sum值。
性质:
与重点相邻的重点不超过sqrt(m)个。
与轻点相邻的所有点不超过sqrt(m)个。
代码:
#include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<utility> #include<cmath> using namespace std; typedef long long LL; const int maxn=1e5+10; vector<int> G[maxn]; pair<int,int> E[maxn]; LL val[maxn],sum[maxn]; int cnt[maxn]; int n,m,q; void init(){ memset(val,0,sizeof(val)); memset(sum,0,sizeof(sum)); memset(cnt,0,sizeof(cnt)); memset(E,0,sizeof(E)); for(int i=1;i<=n;i++) G[i].clear(); } int main(){ int tc; scanf("%d",&tc); while(tc--){ scanf("%d%d",&n,&m); init(); for(int i=0;i<m;i++){ int u,v; scanf("%d%d",&E[i].first,&E[i].second); cnt[E[i].first]++,cnt[E[i].second]++; } for(int i=0;i<m;i++){ int u=E[i].first,v=E[i].second; if(cnt[u]>cnt[v]) swap(u,v); if(cnt[u]<sqrt(m+0.5)){ G[u].push_back(v); if(cnt[v]<sqrt(m+0.5)) G[v].push_back(u); } else{ G[u].push_back(v); G[v].push_back(u); } } scanf("%d",&q); while(q--){ int cmd; scanf("%d",&cmd); if(cmd==0){ int id,v; scanf("%d%d",&id,&v); val[id]+=v; for(int i=0;i<G[id].size();i++){ sum[G[id][i]]+=v; } }else{ int id; scanf("%d",&id); if(cnt[id]>=sqrt(m+0.5)) printf("%lld\n",sum[id]); else{ LL res=0; for(int i=0;i<G[id].size();i++){ res+=val[G[id][i]]; } printf("%lld\n",res); } } } } return 0; }