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; }