ZOJ3742Bellywhite's Algorithm Homework

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3742

  给定n个点m条边的无向图,支持两个操作:

    C x:将与x相邻的边符号取反。

    Q x:

      如果x为'+',输出正边权和。

      如果x为'-',输出负边权和。

      如果x为'A',输出总边权和。

  按度数分块,将度数≥√m的点记为重点,否则为轻点。

  对于重点,我们记录positive_sum和negative_sum,代表相邻的轻-重边正、负边权和。并且记录与之相邻的重点。

  进行修改操作的时候:

    对于重点的取反,我们打上opp标记,修改时取反并更新一下即可。注意重-重边要单独修改。

    对于轻点的取反,我们暴力修改,注意轻-重边的实际边权是opp*边权即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long int64;
typedef unsigned int uint;
const int maxn=50015,maxm=100015;
int n,m,q;
vector<int> w[maxn];
bool heavy[maxn],opp[maxn];
int64 res_p,res_n,sum_p[maxn],sum_n[maxn];
int tot,deg[maxn],now[maxn],pre[maxm],son[maxm],val[maxm];
void connect(int u,int v,int w){pre[++tot]=now[u];now[u]=tot;son[tot]=v;val[tot]=w;}
void initial(){
    res_p=res_n=0;tot=1;
    memset(opp,0,sizeof(opp));
    memset(now,0,sizeof(now));
    memset(deg,0,sizeof(deg));
    memset(heavy,0,sizeof(heavy));
    memset(sum_p,0,sizeof(sum_p));
    memset(sum_n,0,sizeof(sum_n));
    for (int i=1;i<=n;++i) w[i].clear();
}
void init(int cases){
    initial();
    if (scanf("%d%d%d",&n,&m,&q)==EOF) exit(0);
    if (cases>1) printf("\n");
    for (int x,y,v,i=1;i<=m;++i){
        scanf("%d%d%d",&x,&y,&v);
        connect(x,y,v);connect(y,x,v);
        (v>0?res_p:res_n)+=v;++deg[x];++deg[y];
    } 
    for (int lim=sqrt(m),i=1;i<=n;++i) heavy[i]=(deg[i]>lim);
    for (int i=1;i<=n;++i)
        for (int p=now[i];p;p=pre[p])
            if (heavy[i]&&heavy[son[p]]) w[i].push_back(p);
            else (val[p]>0?sum_p[i]:sum_n[i])+=val[p];
}
void query(){
    char op[5];scanf("%s",op);
    switch (op[0]){
        case 'A':printf("%lld\n",res_p+res_n);break;
        case '-':printf("%lld\n",res_n);break;
        case '+':printf("%lld\n",res_p);break;
    }
}
void opposite(int p){
    (val[p]>0?res_p:res_n)-=val[p];
    val[p]=val[p^1]=-val[p];
    (val[p]>0?res_p:res_n)+=val[p];
}
void modify_heavy(int u){
    opp[u]^=1;
    res_p-=sum_p[u];res_n-=sum_n[u];
    swap(sum_p[u],sum_n[u]);sum_p[u]=-sum_p[u];sum_n[u]=-sum_n[u];
    res_p+=sum_p[u];res_n+=sum_n[u];
    for (uint i=0;i<w[u].size();++i) opposite(w[u][i]);
}
void modify_light(int u){
    for (int p=now[u];p;p=pre[p]){
        if (heavy[son[p]]){
            int op=opp[son[p]]?-1:1;
            if (op*val[p]>0){
                res_p-=op*val[p];res_n+=op*-val[p];
                sum_p[son[p]]-=op*val[p];sum_n[son[p]]+=op*-val[p];
            }
            else{
                res_n-=op*val[p];res_p+=op*-val[p];
                sum_n[son[p]]-=op*val[p];sum_p[son[p]]+=op*-val[p]; 
            }
            val[p]=val[p^1]=-val[p];
        }
        else opposite(p);
    }
}
void modify(){
    int x;scanf("%d",&x);
    if (heavy[x]) modify_heavy(x);
    else modify_light(x);
}
void work(){
    for (int i=1;i<=q;++i){
        char op[5];scanf("%s",op);
        switch (op[0]){
            case 'Q':query();break;
            case 'C':modify();break;
        }
    }
}
int cases;
int main(){
    while (1){init(++cases);work();}
    return 0;
}
my code

 

posted @ 2015-08-11 10:34  iamCYY  阅读(258)  评论(0编辑  收藏  举报