zoukankan      html  css  js  c++  java
  • 图的分块

    基本思想是按点的度数划分为重点(deg>=sqrt(m))和轻点(deg<sqrt(m)), 轻点暴力更新, 重点只更新邻接的重点.

    例1. hdu 4858 项目管理

    该题算简单入门了.

    #include <iostream>
    #include <algorithm>
    #include <math.h>
    #include <cstdio>
    #include <vector>
    #define pb push_back
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    using namespace std;
    typedef long long ll;
    
    const int N = 1e5+10, INF = 0x3f3f3f3f;
    int n, m, q, sqn;
    int deg[N], u[N], v[N];
    ll sum[N], val[N];
    vector<int> g[N];
    
    void work() {
    	scanf("%d%d", &n, &m), sqn = sqrt(m);
    	REP(i,1,n) g[i].clear(), deg[i]=sum[i]=val[i]=0;
    	REP(i,1,m) {
    		scanf("%d%d", u+i, v+i);
    		++deg[u[i]], ++deg[v[i]];
    	}
    	REP(i,1,m) {
    		if (deg[u[i]]>=sqn&&deg[v[i]]>=sqn) {
    			g[u[i]].pb(v[i]),g[v[i]].pb(u[i]);
    		}
    		if (deg[u[i]]<sqn) g[u[i]].pb(v[i]);
    		if (deg[v[i]]<sqn) g[v[i]].pb(u[i]);
    	}
    	scanf("%d", &q);
    	REP(i,1,q) {
    		int op, x, v;
    		scanf("%d%d", &op, &x);
    		if (op==0) {
    			scanf("%d", &v);
    			val[x] += v;
    			for (int y:g[x]) if (deg[y]>=sqn) sum[y]+=v;
    		} else {
    			ll ans = 0;
    			if (deg[x]<sqn) for (int y:g[x]) ans += val[y];
    			else ans = sum[x];
    			printf("%lld
    ", ans);
    		}
    	}
    }
    
    int main() {
    	int t;
    	scanf("%d", &t);
    	REP(i,1,t) work();
    }
    

    例2: hdu 4467 Graph

    大意: 每个点都有一个颜色0或1, 每次询问求所有端点颜色为x,y的边权和, 每次修改翻转一个点的颜色.

    思路还是同上题, 对于轻点的修改, 直接暴力. 对于重点的修改只暴力改重点之间的边, 然后再$O(1)$更新重点与轻点的边. 但本题比较卡常, 需要将边离散化去重一下.

    其中$ans$用于记录答案, $val$用于记录每个重点与轻点相连边权和.

    #include <iostream>
    #include <algorithm>
    #include <math.h>
    #include <cstdio>
    #include <set>
    #include <string>
    #include <vector>
    #define pb push_back
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    using namespace std;
    typedef long long ll;
    
    const int N = 1e5+10, INF = 0x3f3f3f3f;
    int n, m, sqn, col[N];
    struct _ {
        int u,v;
        ll w;
        bool operator < (const _ & rhs) const {
            if (u==rhs.u) return v<rhs.v;
            return u<rhs.u;
        }
    } e[N];
    vector<_> g[N];
    ll ans[3], val[N][2];
    int deg[N];
    
    void update(int x) {
        for (_ e:g[x]) {
            ans[col[x]+col[e.v]]-=e.w;
            ans[(col[x]^1)+col[e.v]]+=e.w;
            if (deg[x]<sqn) {
                val[e.v][col[x]]-=e.w;
                val[e.v][col[x]^1]+=e.w;
            }
        }
        if (deg[x]>=sqn) {
            ans[col[x]]-=val[x][0];
            ans[col[x]+1]-=val[x][1];
            ans[col[x]^1]+=val[x][0];
            ans[(col[x]^1)+1]+=val[x][1];
        }
        col[x] ^= 1;
    }
    
    void work() {
        REP(i,1,n) scanf("%d", col+i);
        REP(i,1,n) val[i][0]=val[i][1]=deg[i]=0, g[i].clear();
        REP(i,0,2) ans[i]=0;
        REP(i,1,m) {
            scanf("%d%d%lld", &e[i].u, &e[i].v, &e[i].w);
            if (e[i].u>e[i].v) swap(e[i].u,e[i].v);
        }
        sort(e+1,e+1+m);
        int now = 0;
        REP(i,1,m) {
            if (e[i].u!=e[now].u||e[i].v!=e[now].v) e[++now]=e[i];
            else e[now].w += e[i].w;
        }
        m = now, sqn = sqrt(m);
        REP(i,1,m) { 
            ans[col[e[i].u]+col[e[i].v]] += e[i].w;
            ++deg[e[i].u],++deg[e[i].v];
        }
        REP(i,1,m) {
            if (deg[e[i].u]>=sqn&&deg[e[i].v]>=sqn) {
                g[e[i].u].pb({0,e[i].v,e[i].w});
                g[e[i].v].pb({0,e[i].u,e[i].w});
            }
            if (deg[e[i].u]<sqn) g[e[i].u].pb({0,e[i].v,e[i].w});
            if (deg[e[i].v]<sqn) g[e[i].v].pb({0,e[i].u,e[i].w});
        }
        REP(x,1,n) if (deg[x]<sqn) { 
            for (_ e:g[x]) {
                if (deg[e.v]>=sqn) val[e.v][col[x]]+=e.w;
            }
        }
        int q;
        scanf("%d", &q);
        REP(i,1,q) {
            char s[15];
            int x, y;
            scanf("%s%d", s, &x);
            if (*s=='A') {
                scanf("%d", &y);
                printf("%lld
    ", ans[x+y]);
            } else update(x);
        }
    }
    
    int main() {
        for (int kase = 1; ~scanf("%d%d", &n, &m); ++kase) {
            printf("Case %d:
    ", kase);
            work();
        }
    }
    
  • 相关阅读:
    宏任务、微任务与Event Loop
    puppteer的使用
    docker的使用 -- windows
    vscode集成eslint
    删除git中无用的大文件
    git 使用
    利用chrome devtool 观察页面占用内存
    JS对象-不可扩展对象、密封对象、冻结对象
    数学
    素数 + 背包
  • 原文地址:https://www.cnblogs.com/uid001/p/10434786.html
Copyright © 2011-2022 走看看