这道题展示了分块的强大,学到一手,虽然因为数据太过友好暴力也能过

这道题边数多,直接遍历复杂度很高,大佬们想到了一种分摊复杂度的方法

对于入度大于指定值例如(sqrt),这也是分块常用指定值的点,我们定义为重点

否则为轻点,重点只和重点连,轻点和轻点连。这基于的原理是,重点的个数不超过sqrt个,并且轻点连的边数也不超过sqrt个

对于每个点我们维护val也就是自身加的值,以及sum,周围点的和,对于查询,重点直接输出sum,而轻点进行遍历。

正确的原因是,首先轻点肯定正确,因为是暴力,对于重点来说,所有对于轻点更新的大小,都会通过轻点连向重点的边更新到重点上

同理,重点之间也能相互传递,所以求出sum就是答案。而轻点不能直接输出sum,因为对重点的更新无法传递到轻点,但是因为边数控制住了

所以遍历的复杂度依旧不高。

HDU4858 项目管理(分块)_图论HDU4858 项目管理(分块)_#include_02
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=2e5+20;
typedef long long ll;
int sum[N],val[N];
int in[N];
int st[N];
vector<int> g[N];
int n,m;
struct node{
    int u,v;
}s[N];
void init(){
    int i;
    for(i=0;i<=n;i++){
        sum[i]=val[i]=in[i]=0;
        g[i].clear();
    }
}
int main(){
    int t;
    cin>>t;
    while(t--){
        int i;
        cin>>n>>m;
        init();
        for(i=1;i<=m;i++){
            scanf("%d%d",&s[i].u,&s[i].v);
            in[s[i].u]++;
            in[s[i].v]++;
        }
        int block=sqrt(n);
        for(i=1;i<=n;i++){
            if(in[i]>block)
                st[i]=1;
        }
        for(i=1;i<=m;i++){
            int u=s[i].u;
            int v=s[i].v;
            if(st[u]){
                if(st[v]){
                    g[u].push_back(v);
                    g[v].push_back(u);
                }
                else{
                    g[v].push_back(u);
                }
            }
            else{
                if(st[v]){
                    g[u].push_back(v);
                }
                else{
                    g[u].push_back(v);
                    g[v].push_back(u);
                }
            }
        }
        int q;
        cin>>q;
        while(q--){
            int cmd;
            scanf("%d",&cmd);
            if(cmd){
                int u;
                scanf("%d",&u);
                if(st[u]){
                    printf("%d\n",sum[u]);
                }
                else{
                    int ans=0;
                    for(i=0;i<g[u].size();i++){
                        ans+=val[g[u][i]];
                    }
                    printf("%d\n",ans);
                }
            }
            else{
                int u,v;
                scanf("%d%d",&u,&v);
                val[u]+=v;
                for(i=0;i<g[u].size();i++){
                    int tmp=g[u][i];
                    sum[tmp]+=v;
                }
            }
        }
    }
}
View Code

 

没有人不辛苦,只有人不喊疼