zoukankan      html  css  js  c++  java
  • HDU

    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
    ",sum[u]);
    62                 else{
    63                     ll ans=0ll;
    64                     for(auto to: G[u]) {
    65                         ans+=val[to];
    66                     }
    67                     printf("%I64d
    ",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

    分摊复杂度,点分块。

  • 相关阅读:
    安卓获取双IMEI
    NodeJS异步、同步 创建多层文件夹
    Winfrom 控件名称缩写
    Unobtrusive Ajax
    ID 为 17608的进程当前未运行
    欢迎
    路由
    VS快捷键
    Test
    并查集与带权并查集---由浅入深
  • 原文地址:https://www.cnblogs.com/Kiritsugu/p/9410814.html
Copyright © 2011-2022 走看看