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 }
View Code

分摊复杂度,点分块。

posted on 2018-08-02 23:11  Emiya_Kiritsugu  阅读(201)  评论(0编辑  收藏  举报

导航