zoukankan      html  css  js  c++  java
  • hdu 4467 Graph 构造

    写写思路吧,WA了数十次,都快哭了...改这改那的- -...A了以后都不知道先前哪里写搓了...

    设定一个阀值sqrt(M),当顶点关联的边数量超过阀值,则令其为超级点,否则为普通点,

    若边数量为M,则超级点数量不超过2*sqrt(M),

    证明如下:

      因为,无向图中,假定有2*sqrt(M)个顶点相关联的边至少为sqrt(M),则边数量为, 2*sqrt(M)*sqrt(M)/2 = M, 则意味着边数量大于M,所以矛盾, 得证.

    我们设定一个数组 ans[3],来表示所求结果, 对于每个顶点添加一个sum[2],代表与其关联的顶点颜色为 0/1的边权和.

    假定我们修改一个顶点x 的颜色, 若其颜色为 color, 与其相邻的顶点为0的边权和为sum[0], 顶点为1的边权和为1.

    因为,我们只改变了顶点x的颜色,并未对边权做修改, 那么对最终ans[3]的影响, 只会导致:

         ans[ color+0 ] - sum[0]   &&   ans[color+1] - sum[1]

           ans[ color^1+0 ] + sum[0]   &&   sum[color^1+1] + sum[1]

    这对我们来说是个好消息, 对于每次change操作, 若我们维护每个顶点的sum[0/1],即可维护最终结果数组ans[2][2], 我们再考虑,若change顶点x,

    将会有何种影响.  

        首先对于节点x本身而言, 因为我们记录的sum[0/1],是指其相邻的节点颜色边权和,与x本身颜色无关,则意味着,我们不需要更新.

        对于节点x相邻的节点y而言, y.sum[ x.color ] -= cost(x,y),  y.sum[ x.color^1 ] += cost( x, y ). 

    那么基于此,我们就能够轻松维护题目所需答案了. 但是这里,因为我们每次需要维护其相邻的节点. 最极端情况有 M=10000条边.若10000次

    询问都集中在这里, 那么时间复杂度会达到  10^8 , 5s肯定不够. 这里就用到了最上面的所设定的阀值了.

        我们只对 超过阀值的 超级点维护 sum值, 因为, change操作一个顶点时, 不影响其本身顶点的sum值, 只会修改其相邻的信息.

    但是若我们只用超级点的sum值来维护 ans,显然不行,还有那些普通点未计算. 

        大致思路是, 对于每个修改的顶点,首先修改其 相邻的超级点的sum[0/1]值. 因为超级点的数量不超过 2*sqrt(M),所以复杂度为2sqrt(M).

    若 当前节点x是超级点, 则我们直接可以用其更新 ans数组, 若不是, 则我们需要对当前节点x,统计其所有相邻的sum[0/1]权值和, 然后用sum更新

    ans数组,因为普通点相邻的顶点不超过sqrt(M)个, 则时间复杂度为 sqrt(M).

        假定极端情况 10^5次change操作, 10^5条边. 时间复杂度为  O( Q*sqrt(M) ) . 接近于 10^(7.5) 左右. 解决本题还是足够了.

        总结一下, 很少看到此类的构造, 接近于 O( N^(3/2) )的时间复杂度,来A题. 和上次的那道构造 O( N^(2/3) ) 有异曲同工之妙.

    借助于一个阀值,将操作降低到 sqrt(N)级别. 确实很值得回味. 

         

    View Code
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef long long LL;
    const int N = 101010;
    
    int n, m;
    LL ans[3], sum[N][2];
    vector<LL> c[N];
    vector<int> lin[N];
    int color[N], key[N], deg[N];
    struct node{
        int a,b; LL c;
        bool operator < (const node &tmp)const{
            return (a<tmp.a)||(a==tmp.a&&b<tmp.b);    
        }
    }e[N];
    
    void init(){
        int lim = (int)sqrt(n);        
        for(int i = 0; i <= n; i++) c[i].clear(), lin[i].clear();
        memset( sum, 0, sizeof(sum));
        memset( ans, 0, sizeof(ans));
        memset( key, 0, sizeof(key));
        memset( deg, 0, sizeof(deg));
        for(int i = 1; i <= n; i++) scanf("%d", &color[i] );
        for(int i = 1; i <= m; i++){
            scanf("%d%d%I64d",&e[i].a,&e[i].b,&e[i].c);
            if( e[i].a > e[i].b ) swap( e[i].a, e[i].b );        
        }    
        sort( e+1, e+m+1 );
        int t = 1;
        for(int i = 2; i <= m; i++) 
            if( e[i].a != e[t].a || e[i].b != e[t].b ) e[++t] = e[i];
            else    e[t].c += e[i].c;
        m = t; 
        for(int i = 1; i <= m; i++){
            int a = e[i].a, b = e[i].b; 
            ans[ color[a]+color[b] ] += e[i].c;
            deg[a]++; deg[b]++;    
        }        
        lim = round(sqrt(n));    
        for(int i = 1; i <= n; i++) if( deg[i] > lim ) key[i] = 1;
        for(int i = 1; i <= m; i++){
            int a = e[i].a, b = e[i].b;
            sum[a][ color[b] ] += e[i].c;
            sum[b][ color[a] ] += e[i].c;
            if( key[a] && key[b] ){
                lin[a].push_back(b); c[a].push_back(e[i].c);
                lin[b].push_back(a); c[b].push_back(e[i].c);    
            }     
            if( key[a] == 0 ) lin[a].push_back(b),c[a].push_back(e[i].c);
            if( key[b] == 0 ) lin[b].push_back(a),c[b].push_back(e[i].c);
        }
    }
    void change(int x){
        if( key[x] ){ // 2*sqrt(M)
            for(int i = 0; i < (int)(lin[x].size()); i++){
                sum[ lin[x][i] ][ color[x] ] -= c[x][i];
                sum[ lin[x][i] ][ color[x]^1 ] += c[x][i]; 
            }    
        }
        else{ // sqrt(M)
            sum[x][0] = sum[x][1] = 0;
            for(int i = 0; i < (int)(lin[x].size()); i++){
                sum[x][ color[ lin[x][i] ] ] += c[x][i];
                if( key[ lin[x][i] ] ){
                    sum[ lin[x][i] ][ color[x] ] -= c[x][i];
                    sum[ lin[x][i] ][ color[x]^1 ] += c[x][i];
                }        
            }
        }    
        ans[ color[x]+0 ] -= sum[x][0]; ans[ color[x]+1 ] -= sum[x][1];
        ans[ (color[x]^1)+0 ] += sum[x][0]; ans[ (color[x]^1)+1 ] += sum[x][1];
        color[x] ^= 1;    
    } 
    int main(){
        int Case = 1;
        while( scanf("%d%d",&n,&m) != EOF){
            printf("Case %d:\n", Case++);
            init();
            char op[110]; int Q, a, b;
            scanf("%d", &Q );
            while( Q-- ){
                scanf("%s", op);
                if( op[0] == 'A' ){
                    scanf("%d%d",&a,&b);
                    printf("%I64d\n", ans[a+b] );
                }
                else{
                    scanf("%d",&a);
                    change( a );
                }        
            }
        }
        return 0;
    }
  • 相关阅读:
    [示例] Firemonkey 面包屑导航
    [试玩] FMXLinux (Firemonkey for Linux) Linux 桌面开发(第三方插件)
    [修正] Firemonkey SpeedButton 鼠标移开按钮后 IsPressed 为 False 的问题
    [笔记] FireDAC DataSet 导入及导出 JSON
    [笔记] 升級到 Delphi 10.2 Tokyo 笔记
    [示例] 用代码设置 ListView 颜色 (只适用 Win 平台,无需修改官方源码)
    [上架] iOS 上架更新版本号建议
    [教学] Delphi IDE 文件搜寻功能
    Loadrunner相关问题
    数据导出excel数据丢失
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/3053653.html
Copyright © 2011-2022 走看看