HDU - 4858 项目管理
N个点,M条无向边。现在有Q组操作,一种是给 i号点增加能量,一种是询问 i号点相邻点的能量和(点间有多条边就算两次)。
据说暴力能过,但还是用这题学习了一下 点分块 。 度数不超过 sqrt(M) 的为 "轻点", 否则为 "重点","轻点"可以指向(连向)这两种点,但"重点"只能指向(连向)"重点" 。val[i]表示i号点能量,sum[i]维护i号点所有相邻的能量。"增加能量"时更新i号点相邻点j的sum[j],查询时"轻点"暴力搜,"重点"直接O(1)返回 sum[i]即可。
修改时,"轻点"们可以修改"重点","重点"可以修改"重点","重点"的sum[]是被维护的,而"轻点"只有sqrt(M)条边,爆搜没问题。
ps : 似乎"重点"出度不超过 2*sqrt(M),未证明。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define fst first 4 #define scd second 5 #define pb(x) push_back((x)) 6 #define mkp(x,y) make_pair((x),(y)) 7 #define ist(x) insert((x)) 8 typedef long long ll; 9 typedef pair<int ,int > pii; 10 typedef pair<ll ,ll > pll; 11 typedef vector< int > vi; 12 ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);} 13 ll qPow(ll a,ll b,ll mod){ ll ret=1ll;while(b){ if(b&1) ret=ret*a%mod;a=a*a%mod;b>>=1;} return ret; } 14 15 const int maxn=100100; 16 int degree[maxn]; 17 vi G[maxn]; 18 ll val[maxn]; 19 ll sum[maxn]; 20 pii bian[maxn]; 21 int bound; 22 23 void addedge(int u,int v){ 24 if(degree[u]<=bound) G[u].pb(v); 25 else if(degree[v]>bound) G[u].pb(v); 26 } 27 28 int main(){ 29 int T; 30 scanf("%d",&T); 31 while(T--) { 32 int N,M; 33 scanf("%d%d",&N,&M); 34 for(int i=1;i<=N;++i){ 35 degree[i]=0; 36 G[i].clear(); 37 val[i]=0ll; 38 sum[i]=0ll; 39 } 40 for(int i=1;i<=M;++i){ 41 int u,v; 42 scanf("%d%d",&u,&v); 43 pii tmp=mkp(u,v); 44 degree[u]++,degree[v]++; 45 bian[i]=tmp; 46 } 47 bound=sqrt(M); 48 for(int i=1;i<=M;++i) 49 { 50 int u=bian[i].fst,v=bian[i].scd; 51 addedge(u,v); 52 addedge(v,u); 53 } 54 int Q; 55 scanf("%d",&Q); 56 for(int i=0;i<Q;++i){ 57 int op; 58 scanf("%d",&op); 59 if(op){ 60 int u;scanf("%d",&u); 61 if(degree[u]>bound) printf("%I64d\n",sum[u]); 62 else{ 63 ll ans=0ll; 64 for(auto to: G[u]) { 65 ans+=val[to]; 66 } 67 printf("%I64d\n",ans); 68 } 69 } 70 else{ 71 int u,w;scanf("%d%d",&u,&w); 72 val[u]+=1ll*w; 73 for(auto to: G[u]){ 74 sum[to]+=1ll*w; 75 } 76 } 77 } 78 } 79 return 0; 80 }
分摊复杂度,点分块。
posted on 2018-08-02 23:11 Emiya_Kiritsugu 阅读(201) 评论(0) 编辑 收藏 举报