HDU 4467 Graph(图论+暴力)(2012 Asia Chengdu Regional Contest)

Description

P. T. Tigris is a student currently studying graph theory. One day, when he was studying hard, GS appeared around the corner shyly and came up with a problem: 
Given a graph with n nodes and m undirected weighted edges, every node having one of two colors, namely black (denoted as 0) and white (denoted as 1), you’re to maintain q operations of either kind: 
* Change x: Change the color of x th node. A black node should be changed into white one and vice versa. 
* Asksum A B: Find the sum of weight of those edges whose two end points are in color A and B respectively. A and B can be either 0 or 1. 
P. T. Tigris doesn’t know how to solve this problem, so he turns to you for help.
 

Input

There are several test cases. 
For each test case, the first line contains two integers, n and m (1 ≤ n,m ≤ 10 5), where n is the number of nodes and m is the number of edges. 
The second line consists of n integers, the i th of which represents the color of the i th node: 0 for black and 1 for white. 
The following m lines represent edges. Each line has three integer u, v and w, indicating there is an edge of weight w (1 ≤ w ≤ 2 31 - 1) between u and v (u != v). 
The next line contains only one integer q (1 ≤ q ≤ 10 5), the number of operations. 
Each of the following q lines describes an operation mentioned before. 
Input is terminated by EOF.
 

Output

For each test case, output several lines. 
The first line contains “Case X:”, where X is the test case number (starting from 1). 
And then, for each “Asksum” query, output one line containing the desired answer.
 
题目大意:给n个点m条无向边,每个点有一个颜色(0 or 1),每条边有一个权值。有q个询问,或翻转某个结点的颜色,或询问一个点的颜色为x、另一个点的颜色为y的边的权和。
思路:直接暴力复杂度高达O(qm),完全无法承受。好像没有其他方法,我们只能暴力地优美一点。
用一个sum[]记录答案,询问的时候O(1)输出。
记deg[u]为结点u的度,对于所有deg[v]<deg[u],连一条边v→u。
state[u]记录对于所有deg[v]<deg[u]的v↔u的权值和。
当修改u的时候,对于所有deg[v]<deg[u],利用state直接修改。对于deg[v]≥deg[u],一个一个修改。
对于一个无重边的图来讲,对每个点来说,所有度数大于等于它的点不超过$ O(sqrt{m}) $个(因为若一个点的度数为$k$,那么度数大于等于它的点最多$x leq k$个,这些点的度数总和至少是$k^2$,由于$k^2<=2 imes m$,所以$O(x)=O(sqrt m)$)
那么时间复杂度为$O(q imes sqrt m )$
这题要去重边(权和相加)。不去重边,2个点10W条边你还得死……
 
代码(3187MS):
  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <algorithm>
  5 using namespace std;
  6 typedef long long LL;
  7 
  8 const int MAXN = 100010;
  9 const int MAXE = 200010;
 10 
 11 struct Edge {
 12     int from, to, del;
 13     LL w;
 14     void read() {
 15         scanf("%d%d%I64d", &from, &to, &w);
 16         del = 0;
 17         if(from > to) swap(from, to);
 18     }
 19     bool operator < (const Edge &rhs) const {
 20         if(from != rhs.from) return from < rhs.from;
 21         return to < rhs.to;
 22     }
 23     bool operator == (const Edge &rhs) const {
 24         return from == rhs.from && to == rhs.to;
 25     }
 26 } edge[MAXE];
 27 
 28 LL sum[3];
 29 int n, m, q;
 30 int head[MAXN], deg[MAXN], ecnt;
 31 int col[MAXN];
 32 LL state[MAXN][2];
 33 int to[MAXE], next[MAXE], dir[MAXE];
 34 LL weight[MAXE];
 35 
 36 void init() {
 37     memset(head, 0, sizeof(head));
 38     memset(sum, 0, sizeof(sum));
 39     memset(deg, 0, sizeof(deg));
 40     memset(state, 0, sizeof(state));
 41     ecnt = 2;
 42 }
 43 
 44 void add_edge(int u, int v, LL w, bool flag) {
 45     to[ecnt] = v; weight[ecnt] = w; dir[ecnt] = flag; next[ecnt] = head[u]; head[u] = ecnt++;
 46 }
 47 
 48 void change() {
 49     int x, c;
 50     scanf("%d", &x);
 51     c = col[x]; col[x] = !col[x];
 52     sum[c] -= state[x][0];
 53     sum[c + 1] -= state[x][1];
 54     sum[col[x]] += state[x][0];
 55     sum[col[x] + 1] += state[x][1];
 56     for(int p = head[x]; p; p = next[p]) {
 57         int &v = to[p];
 58         if(!dir[p]) {
 59             state[v][c] -= weight[p];
 60             state[v][col[x]] += weight[p];
 61         }
 62         sum[c + col[v]] -= weight[p];
 63         sum[col[x] + col[v]] += weight[p];
 64     }
 65 }
 66 
 67 char s[10];
 68 
 69 int main() {
 70     int t = 0;
 71     while(scanf("%d%d", &n, &m) != EOF) {
 72         init();
 73         for(int i = 1; i <= n; ++i) scanf("%d", &col[i]);
 74         for(int i = 1; i <= m; ++i) {
 75             edge[i].read();
 76             sum[col[edge[i].from] + col[edge[i].to]] += edge[i].w;
 77         }
 78         printf("Case %d:
", ++t);
 79         sort(edge + 1, edge + m + 1);
 80         for(int i = 1; i < m; ++i) {
 81             if(edge[i] == edge[i + 1]) {
 82                 edge[i].del = true;
 83                 edge[i + 1].w += edge[i].w;
 84             } else {
 85                 ++deg[edge[i].from], ++deg[edge[i].to];
 86             }
 87         }
 88         for(int i = 1; i <= m; ++i) {
 89             if(edge[i].del) continue;
 90             if(deg[edge[i].from] < deg[edge[i].to]) {
 91                 add_edge(edge[i].from, edge[i].to, edge[i].w, 0);
 92                 state[edge[i].to][col[edge[i].from]] += edge[i].w;
 93             } else if(deg[edge[i].from] > deg[edge[i].to]) {
 94                 add_edge(edge[i].to, edge[i].from, edge[i].w, 0);
 95                 state[edge[i].from][col[edge[i].to]] += edge[i].w;
 96             } else {
 97                 add_edge(edge[i].from, edge[i].to, edge[i].w, 1);
 98                 add_edge(edge[i].to, edge[i].from, edge[i].w, 1);
 99             }
100         }
101         scanf("%d", &q);
102         while(q--) {
103             scanf("%s", s);
104             if(*s == 'A') {
105                 int x, y;
106                 scanf("%d%d", &x, &y);
107                 printf("%I64d
", sum[x + y]);
108             } else change();
109         }
110     }
111 }
View Code

代码(3078MS)(稍微改了一下):

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <algorithm>
  5 using namespace std;
  6 typedef long long LL;
  7 
  8 const int MAXN = 100010;
  9 const int MAXE = 200010;
 10 
 11 struct Edge {
 12     int from, to, del;
 13     LL w;
 14     void read() {
 15         scanf("%d%d%I64d", &from, &to, &w);
 16         del = 0;
 17         if(from > to) swap(from, to);
 18     }
 19     bool operator < (const Edge &rhs) const {
 20         if(from != rhs.from) return from < rhs.from;
 21         return to < rhs.to;
 22     }
 23     bool operator == (const Edge &rhs) const {
 24         return from == rhs.from && to == rhs.to;
 25     }
 26 } edge[MAXE];
 27 
 28 LL sum[3];
 29 int n, m, q;
 30 int head[MAXN], deg[MAXN], ecnt;
 31 int col[MAXN];
 32 LL state[MAXN][2];
 33 int to[MAXE], next[MAXE];
 34 LL weight[MAXE];
 35 
 36 void init() {
 37     memset(head, 0, sizeof(head));
 38     memset(sum, 0, sizeof(sum));
 39     memset(deg, 0, sizeof(deg));
 40     memset(state, 0, sizeof(state));
 41     ecnt = 2;
 42 }
 43 
 44 void add_edge(int u, int v, LL w) {
 45     to[ecnt] = v; weight[ecnt] = w; next[ecnt] = head[u]; head[u] = ecnt++;
 46 }
 47 
 48 void change() {
 49     int x, c;
 50     scanf("%d", &x);
 51     c = col[x]; col[x] = !col[x];
 52     sum[c] -= state[x][0];
 53     sum[c + 1] -= state[x][1];
 54     sum[col[x]] += state[x][0];
 55     sum[col[x] + 1] += state[x][1];
 56     for(int p = head[x]; p; p = next[p]) {
 57         int &v = to[p];
 58         state[v][c] -= weight[p];
 59         state[v][col[x]] += weight[p];
 60         sum[c + col[v]] -= weight[p];
 61         sum[col[x] + col[v]] += weight[p];
 62     }
 63 }
 64 
 65 char s[10];
 66 
 67 int main() {
 68     int t = 0;
 69     while(scanf("%d%d", &n, &m) != EOF) {
 70         init();
 71         for(int i = 1; i <= n; ++i) scanf("%d", &col[i]);
 72         for(int i = 1; i <= m; ++i) {
 73             edge[i].read();
 74             sum[col[edge[i].from] + col[edge[i].to]] += edge[i].w;
 75         }
 76         printf("Case %d:
", ++t);
 77         sort(edge + 1, edge + m + 1);
 78         for(int i = 1; i < m; ++i) {
 79             if(edge[i] == edge[i + 1]) {
 80                 edge[i].del = true;
 81                 edge[i + 1].w += edge[i].w;
 82             } else {
 83                 ++deg[edge[i].from], ++deg[edge[i].to];
 84             }
 85         }
 86         for(int i = 1; i <= m; ++i) {
 87             if(edge[i].del) continue;
 88             if(deg[edge[i].from] < deg[edge[i].to]) {
 89                 add_edge(edge[i].from, edge[i].to, edge[i].w);
 90                 state[edge[i].to][col[edge[i].from]] += edge[i].w;
 91             } else {
 92                 add_edge(edge[i].to, edge[i].from, edge[i].w);
 93                 state[edge[i].from][col[edge[i].to]] += edge[i].w;
 94             }
 95         }
 96         scanf("%d", &q);
 97         while(q--) {
 98             scanf("%s", s);
 99             if(*s == 'A') {
100                 int x, y;
101                 scanf("%d%d", &x, &y);
102                 printf("%I64d
", sum[x + y]);
103             } else change();
104         }
105     }
106 }
View Code
原文地址:https://www.cnblogs.com/oyking/p/3376684.html