n个点,m条无向边边有权值,(1 ≤ n,m ≤ 10 5) 。每个点不是黑色就是白色,以0或1区分。
有q组操作(1 ≤ q ≤ 10 5),分为两种:一种是将i号点的颜色改变,一种是给出两个颜色(可以相同),询问图中所有两端是这两种颜色的边的权值之和。
暴力的想法很好想,我们用ans[0] ans[1] ans[2] 分别记录 同黑 、 异色 、同白 的答案,每次改i号点颜色时就遍历所有与i号点相邻的点,以之修改 三个ans ,但这一看就会TLE。
还是用点分块,分轻重点,(见HDU - 4858 项目管理 ) ,i号点是重点,则sum[0][i]维护其到相邻的黑色点的和,sum[1][i]维护白色。
改变颜色时修改ans,轻点爆搜修改,重点根据sum[][i]修改答案。但无论轻重点,都要修改其指向的重点的sum[][i]。
ps : 这题需要把预处理等价的边全部合并,否则还是会TLE。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define fst first 4 #define scd second 5 #define pb(x) push_back((x)) 6 #define mkp(x,y) make_pair((x),(y)) 7 #define ist(x) insert((x)) 8 typedef long long ll; 9 typedef pair<int ,int > pii; 10 typedef pair<ll ,ll > pll; 11 typedef vector< int > vi; 12 ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);} 13 ll qPow(ll a,ll b,ll mod){ ll ret=1ll;while(b){ if(b&1) ret=ret*a%mod;a=a*a%mod;b>>=1;} return ret; } 14 15 const int maxn=1e5+5; 16 17 struct Edge{ 18 int to; 19 ll weight; 20 Edge(int v,ll w):to(v),weight(w) {} 21 }; 22 23 struct Bian{ 24 int u; 25 int v; 26 ll wei; 27 Bian(int a,int b,ll c):u(a),v(b),wei(c) {} 28 Bian(){}; 29 }; 30 ll ans[3]; 31 int degree[maxn]; 32 ll sum[2][maxn]; 33 int col[maxn]; 34 vector< Edge > G[maxn]; 35 Bian bin[maxn]; 36 Bian raw[maxn]; 37 bool heavy[maxn]; 38 int bound; 39 40 void addedge(int u,int v,ll w){ 41 if(!heavy[u]) G[u].pb(Edge(v,w)); 42 else if(heavy[v]) G[u].pb(Edge(v,w)); 43 } 44 45 bool cmp(Bian a,Bian b){ 46 if(a.u!=b.u) return a.u<b.u; 47 return a.v<b.v; 48 } 49 50 int main(){ 51 //freopen("data.in","r",stdin); 52 //freopen("data.out","w",stdout); 53 int N,M; 54 int cntcase=1; 55 while(~scanf("%d%d",&N,&M)){ 56 for(int i=1;i<=N;++i) scanf("%d",&col[i]); 57 for(int i=1;i<=N;++i){ 58 degree[i]=0; 59 sum[0][i]=0ll;sum[1][i]=0ll; 60 G[i].clear(); 61 heavy[i]=false; 62 } 63 ans[0]=ans[1]=ans[2]=0ll; 64 for(int i=1;i<=M;++i){ 65 int u,v; 66 ll w;scanf("%d%d%lld",&u,&v,&w); 67 if(u>v) swap(u,v); 68 Bian tmp=Bian(u,v,w); 69 //degree[u]++,degree[v]++; 70 raw[i] = tmp; 71 } 72 sort(raw+1,raw+1+M,cmp); 73 //for(int i=1;i<=M;++i) printf("%d - %d : %lld ",raw[i].u,raw[i].v,raw[i].wei); 74 int cntedge=0; 75 for(int i=1,j=2;i<=M;i=j){ 76 for(j=i+1;j<=M;++j){ 77 if(raw[i].u==raw[j].u&&raw[i].v==raw[j].v) 78 { 79 raw[i].wei+=raw[j].wei; 80 } 81 else break; 82 } 83 bin[++cntedge]=raw[i]; 84 } 85 int bound=sqrt(cntedge); 86 for(int i=1;i<=cntedge;++i){ 87 //printf("%d - %d : %lld ",bin[i].u,bin[i].v,bin[i].wei); 88 degree[bin[i].u]++; 89 degree[bin[i].v]++; 90 } 91 for(int i=1;i<=N;++i) if(degree[i]>bound) heavy[i]=true; 92 for(int i=1;i<=cntedge;++i){ 93 int u,v; 94 u=bin[i].u,v=bin[i].v; 95 ll w; 96 w=bin[i].wei; 97 addedge(u,v,w); 98 addedge(v,u,w); 99 ans[col[u]+col[v]]+=w; 100 if(heavy[v]){ 101 sum[col[u]][v]+=w; 102 } 103 if(heavy[u]){ 104 sum[col[v]][u]+=w; 105 } 106 } 107 /* 108 for(int i=0;i<3;++i) printf("ans [%d]: %lld ",i,ans[i]); 109 for(int i=0;i<2;++i){ 110 for(int j=1;j<=N;++j){ 111 printf("sum [%d][%d] : %lld ",i,j,sum[i][j]); 112 } 113 } 114 */ 115 printf("Case %d: ",cntcase++); 116 int Q;scanf("%d",&Q); 117 for(int i=0;i<Q;++i){ 118 char op[10];scanf("%s",op); 119 if(op[0]=='A'){ 120 int aa,bb;scanf("%d%d",&aa,&bb) ; 121 printf("%I64d ",ans[aa+bb]); 122 } 123 else{ 124 int u;scanf("%d",&u); 125 if(!heavy[u]){ 126 for(auto e : G[u]){ 127 int to=e.to; 128 ll wei=e.weight; 129 //printf("light %d -> %d : %d ",u,to,wei); 130 if(heavy[to]){ 131 sum[col[u]][to]-=wei; 132 sum[(col[u]^1)][to]+=wei; 133 } 134 ans[col[u]+col[to]]-=wei; 135 ans[(col[u]^1)+col[to]]+=wei; 136 //for(int i=0;i<3;++i) printf("ans [%d]: %lld ",i,ans[i]); 137 } 138 col[u]^=1; 139 } 140 else{ 141 ans[col[u]+0]-=sum[0][u]; 142 ans[col[u]+1]-=sum[1][u]; 143 ans[(col[u]^1)+0]+=sum[0][u]; 144 ans[(col[u]^1)+1]+=sum[1][u]; 145 //for(int i=0;i<3;++i) printf("ans [%d]: %lld ",i,ans[i]); 146 for(auto e : G[u]){ 147 int to=e.to; 148 ll wei=e.weight; 149 //printf("heavy : %d -> %d : %d ",u,to,wei); 150 sum[col[u]][to]-=wei; 151 sum[(col[u]^1)][to]+=wei; 152 } 153 col[u]^=1; 154 } 155 //for(int i=1;i<=N;++i) printf(" %d ",col[i]); 156 //puts(""); 157 //for(int i=0;i<3;++i) printf("ans [%d]: %lld ",i,ans[i]); 158 } 159 } 160 } 161 return 0; 162 }
等一下,既然重点也要搜,为何不“一视同仁”。无论轻重,都用sum[][i]修改,然后搜索修改其指向的点的sum[][i]。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define fst first 4 #define scd second 5 #define pb(x) push_back((x)) 6 #define mkp(x,y) make_pair((x),(y)) 7 #define ist(x) insert((x)) 8 typedef long long ll; 9 typedef pair<int ,int > pii; 10 typedef pair<ll ,ll > pll; 11 typedef vector< int > vi; 12 ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);} 13 ll qPow(ll a,ll b,ll mod){ ll ret=1ll;while(b){ if(b&1) ret=ret*a%mod;a=a*a%mod;b>>=1;} return ret; } 14 15 const int maxn=1e5+5; 16 17 struct Edge{ 18 int to; 19 ll weight; 20 Edge(int v,ll w):to(v),weight(w) {} 21 }; 22 23 struct Bian{ 24 int u; 25 int v; 26 ll wei; 27 Bian(int a,int b,ll c):u(a),v(b),wei(c) {} 28 Bian(){}; 29 }; 30 ll ans[3]; 31 int degree[maxn]; 32 ll sum[2][maxn]; 33 int col[maxn]; 34 vector< Edge > G[maxn]; 35 Bian bin[maxn]; 36 Bian raw[maxn]; 37 bool heavy[maxn]; 38 int bound; 39 40 void addedge(int u,int v,ll w){ 41 if(!heavy[u]) G[u].pb(Edge(v,w)); 42 else if(heavy[v]) G[u].pb(Edge(v,w)); 43 } 44 45 bool cmp(Bian a,Bian b){ 46 if(a.u!=b.u) return a.u<b.u; 47 return a.v<b.v; 48 } 49 50 int main(){ 51 //freopen("data.in","r",stdin); 52 //freopen("data.out","w",stdout); 53 int N,M; 54 int cntcase=1; 55 while(~scanf("%d%d",&N,&M)){ 56 for(int i=1;i<=N;++i) scanf("%d",&col[i]); 57 for(int i=1;i<=N;++i){ 58 degree[i]=0; 59 sum[0][i]=0ll;sum[1][i]=0ll; 60 G[i].clear(); 61 heavy[i]=false; 62 } 63 ans[0]=ans[1]=ans[2]=0ll; 64 for(int i=1;i<=M;++i){ 65 int u,v; 66 ll w;scanf("%d%d%lld",&u,&v,&w); 67 if(u>v) swap(u,v); 68 Bian tmp=Bian(u,v,w); 69 //degree[u]++,degree[v]++; 70 raw[i] = tmp; 71 } 72 sort(raw+1,raw+1+M,cmp); 73 //for(int i=1;i<=M;++i) printf("%d - %d : %lld ",raw[i].u,raw[i].v,raw[i].wei); 74 int cntedge=0; 75 for(int i=1,j=2;i<=M;i=j){ 76 for(j=i+1;j<=M;++j){ 77 if(raw[i].u==raw[j].u&&raw[i].v==raw[j].v) 78 { 79 raw[i].wei+=raw[j].wei; 80 } 81 else break; 82 } 83 bin[++cntedge]=raw[i]; 84 } 85 int bound=sqrt(cntedge); 86 for(int i=1;i<=cntedge;++i){ 87 //printf("%d - %d : %lld ",bin[i].u,bin[i].v,bin[i].wei); 88 degree[bin[i].u]++; 89 degree[bin[i].v]++; 90 } 91 for(int i=1;i<=N;++i) if(degree[i]>bound) heavy[i]=true; 92 for(int i=1;i<=cntedge;++i){ 93 int u,v; 94 u=bin[i].u,v=bin[i].v; 95 ll w; 96 w=bin[i].wei; 97 addedge(u,v,w); 98 addedge(v,u,w); 99 ans[col[u]+col[v]]+=w; 100 sum[col[u]][v]+=w; 101 sum[col[v]][u]+=w; 102 } 103 /* 104 for(int i=0;i<3;++i) printf("ans [%d]: %lld ",i,ans[i]); 105 for(int i=0;i<2;++i){ 106 for(int j=1;j<=N;++j){ 107 printf("sum [%d][%d] : %lld ",i,j,sum[i][j]); 108 } 109 } 110 */ 111 printf("Case %d: ",cntcase++); 112 int Q;scanf("%d",&Q); 113 for(int i=0;i<Q;++i){ 114 char op[10];scanf("%s",op); 115 if(op[0]=='A'){ 116 int aa,bb;scanf("%d%d",&aa,&bb) ; 117 printf("%I64d ",ans[aa+bb]); 118 } 119 else{ 120 int u;scanf("%d",&u); 121 //if(!heavy[u]){ 122 ans[col[u]+0]-=sum[0][u]; 123 ans[col[u]+1]-=sum[1][u]; 124 ans[(col[u]^1)+0]+=sum[0][u]; 125 ans[(col[u]^1)+1]+=sum[1][u]; 126 for(auto e : G[u]){ 127 int to=e.to; 128 ll wei=e.weight; 129 //printf("light %d -> %d : %d ",u,to,wei); 130 sum[col[u]][to]-=wei; 131 sum[(col[u]^1)][to]+=wei; 132 //for(int i=0;i<3;++i) printf("ans [%d]: %lld ",i,ans[i]); 133 } 134 col[u]^=1; 135 //} 136 /* 137 else{ 138 ans[col[u]+0]-=sum[0][u]; 139 ans[col[u]+1]-=sum[1][u]; 140 ans[(col[u]^1)+0]+=sum[0][u]; 141 ans[(col[u]^1)+1]+=sum[1][u]; 142 //for(int i=0;i<3;++i) printf("ans [%d]: %lld ",i,ans[i]); 143 for(auto e : G[u]){ 144 int to=e.to; 145 ll wei=e.weight; 146 //printf("heavy : %d -> %d : %d ",u,to,wei); 147 sum[col[u]][to]-=wei; 148 sum[(col[u]^1)][to]+=wei; 149 } 150 col[u]^=1; 151 } 152 */ 153 //for(int i=1;i<=N;++i) printf(" %d ",col[i]); 154 //puts(""); 155 //for(int i=0;i<3;++i) printf("ans [%d]: %lld ",i,ans[i]); 156 } 157 } 158 } 159 return 0; 160 }
想象一下轻重点的连接关系,分块实在是厉害。
2018.08.13
"一视同仁" 其实还是搞错的,像下面这组数据,先改 重点 再改轻点,会出错。因为修改重点的影响 无法传给 轻点的sum[][i]。
os:能AC纯属数据出的弱吧。
5 4
0 0 0 0 0
1 5 1
2 5 2
3 5 3
4 5 4
11
Asksum 0 0
Asksum 0 1
Asksum 1 1
Change 5
Asksum 0 0
Asksum 0 1
Asksum 1 1
Change 1
Asksum 0 0
Asksum 0 1
Asksum 1 1
还是老老实实 轻点爆搜修改,重点用sum[][i]改吧。
时刻谨记 : 轻点影响轻重点 ,重点只影响重点。