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 \times m$,所以$O(x)=O(\sqrt m)$)
那么时间复杂度为$O(q \times \sqrt m )$
这题要去重边(权和相加)。不去重边,2个点10W条边你还得死……
 
代码(3187MS):
 #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL; const int MAXN = ;
const int MAXE = ; struct Edge {
int from, to, del;
LL w;
void read() {
scanf("%d%d%I64d", &from, &to, &w);
del = ;
if(from > to) swap(from, to);
}
bool operator < (const Edge &rhs) const {
if(from != rhs.from) return from < rhs.from;
return to < rhs.to;
}
bool operator == (const Edge &rhs) const {
return from == rhs.from && to == rhs.to;
}
} edge[MAXE]; LL sum[];
int n, m, q;
int head[MAXN], deg[MAXN], ecnt;
int col[MAXN];
LL state[MAXN][];
int to[MAXE], next[MAXE], dir[MAXE];
LL weight[MAXE]; void init() {
memset(head, , sizeof(head));
memset(sum, , sizeof(sum));
memset(deg, , sizeof(deg));
memset(state, , sizeof(state));
ecnt = ;
} void add_edge(int u, int v, LL w, bool flag) {
to[ecnt] = v; weight[ecnt] = w; dir[ecnt] = flag; next[ecnt] = head[u]; head[u] = ecnt++;
} void change() {
int x, c;
scanf("%d", &x);
c = col[x]; col[x] = !col[x];
sum[c] -= state[x][];
sum[c + ] -= state[x][];
sum[col[x]] += state[x][];
sum[col[x] + ] += state[x][];
for(int p = head[x]; p; p = next[p]) {
int &v = to[p];
if(!dir[p]) {
state[v][c] -= weight[p];
state[v][col[x]] += weight[p];
}
sum[c + col[v]] -= weight[p];
sum[col[x] + col[v]] += weight[p];
}
} char s[]; int main() {
int t = ;
while(scanf("%d%d", &n, &m) != EOF) {
init();
for(int i = ; i <= n; ++i) scanf("%d", &col[i]);
for(int i = ; i <= m; ++i) {
edge[i].read();
sum[col[edge[i].from] + col[edge[i].to]] += edge[i].w;
}
printf("Case %d:\n", ++t);
sort(edge + , edge + m + );
for(int i = ; i < m; ++i) {
if(edge[i] == edge[i + ]) {
edge[i].del = true;
edge[i + ].w += edge[i].w;
} else {
++deg[edge[i].from], ++deg[edge[i].to];
}
}
for(int i = ; i <= m; ++i) {
if(edge[i].del) continue;
if(deg[edge[i].from] < deg[edge[i].to]) {
add_edge(edge[i].from, edge[i].to, edge[i].w, );
state[edge[i].to][col[edge[i].from]] += edge[i].w;
} else if(deg[edge[i].from] > deg[edge[i].to]) {
add_edge(edge[i].to, edge[i].from, edge[i].w, );
state[edge[i].from][col[edge[i].to]] += edge[i].w;
} else {
add_edge(edge[i].from, edge[i].to, edge[i].w, );
add_edge(edge[i].to, edge[i].from, edge[i].w, );
}
}
scanf("%d", &q);
while(q--) {
scanf("%s", s);
if(*s == 'A') {
int x, y;
scanf("%d%d", &x, &y);
printf("%I64d\n", sum[x + y]);
} else change();
}
}
}

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

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL; const int MAXN = ;
const int MAXE = ; struct Edge {
int from, to, del;
LL w;
void read() {
scanf("%d%d%I64d", &from, &to, &w);
del = ;
if(from > to) swap(from, to);
}
bool operator < (const Edge &rhs) const {
if(from != rhs.from) return from < rhs.from;
return to < rhs.to;
}
bool operator == (const Edge &rhs) const {
return from == rhs.from && to == rhs.to;
}
} edge[MAXE]; LL sum[];
int n, m, q;
int head[MAXN], deg[MAXN], ecnt;
int col[MAXN];
LL state[MAXN][];
int to[MAXE], next[MAXE];
LL weight[MAXE]; void init() {
memset(head, , sizeof(head));
memset(sum, , sizeof(sum));
memset(deg, , sizeof(deg));
memset(state, , sizeof(state));
ecnt = ;
} void add_edge(int u, int v, LL w) {
to[ecnt] = v; weight[ecnt] = w; next[ecnt] = head[u]; head[u] = ecnt++;
} void change() {
int x, c;
scanf("%d", &x);
c = col[x]; col[x] = !col[x];
sum[c] -= state[x][];
sum[c + ] -= state[x][];
sum[col[x]] += state[x][];
sum[col[x] + ] += state[x][];
for(int p = head[x]; p; p = next[p]) {
int &v = to[p];
state[v][c] -= weight[p];
state[v][col[x]] += weight[p];
sum[c + col[v]] -= weight[p];
sum[col[x] + col[v]] += weight[p];
}
} char s[]; int main() {
int t = ;
while(scanf("%d%d", &n, &m) != EOF) {
init();
for(int i = ; i <= n; ++i) scanf("%d", &col[i]);
for(int i = ; i <= m; ++i) {
edge[i].read();
sum[col[edge[i].from] + col[edge[i].to]] += edge[i].w;
}
printf("Case %d:\n", ++t);
sort(edge + , edge + m + );
for(int i = ; i < m; ++i) {
if(edge[i] == edge[i + ]) {
edge[i].del = true;
edge[i + ].w += edge[i].w;
} else {
++deg[edge[i].from], ++deg[edge[i].to];
}
}
for(int i = ; i <= m; ++i) {
if(edge[i].del) continue;
if(deg[edge[i].from] < deg[edge[i].to]) {
add_edge(edge[i].from, edge[i].to, edge[i].w);
state[edge[i].to][col[edge[i].from]] += edge[i].w;
} else {
add_edge(edge[i].to, edge[i].from, edge[i].w);
state[edge[i].from][col[edge[i].to]] += edge[i].w;
}
}
scanf("%d", &q);
while(q--) {
scanf("%s", s);
if(*s == 'A') {
int x, y;
scanf("%d%d", &x, &y);
printf("%I64d\n", sum[x + y]);
} else change();
}
}
}

HDU 4467 Graph(图论+暴力)(2012 Asia Chengdu Regional Contest)的更多相关文章

  1. HDU 4468 Spy(KMP+贪心)(2012 Asia Chengdu Regional Contest)

    Description “Be subtle! Be subtle! And use your spies for every kind of business. ”― Sun Tzu“A spy w ...

  2. 2012 Asia Chengdu Regional Contest

    Browsing History http://acm.hdu.edu.cn/showproblem.php?pid=4464 签到 #include<cstdio> #include&l ...

  3. HDU-4432-Sum of divisors ( 2012 Asia Tianjin Regional Contest )

    Sum of divisors Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  4. HDU 4436 str2int(后缀自动机)(2012 Asia Tianjin Regional Contest)

    Problem Description In this problem, you are given several strings that contain only digits from '0' ...

  5. HDU 4433 locker 2012 Asia Tianjin Regional Contest 减少国家DP

    意甲冠军:给定的长度可达1000数的顺序,图像password像锁.可以上下滑动,同时会0-9周期. 每个操作.最多三个数字连续操作.现在给出的起始序列和靶序列,获得操作的最小数量,从起始序列与靶序列 ...

  6. HDU 4115 Eliminate the Conflict(2-SAT)(2011 Asia ChengDu Regional Contest)

    Problem Description Conflicts are everywhere in the world, from the young to the elderly, from famil ...

  7. HDU 4441 Queue Sequence(优先队列+Treap树)(2012 Asia Tianjin Regional Contest)

    Problem Description There's a queue obeying the first in first out rule. Each time you can either pu ...

  8. HDU 4433 locker(DP)(2012 Asia Tianjin Regional Contest)

    Problem Description A password locker with N digits, each digit can be rotated to 0-9 circularly.You ...

  9. HDU 4431 Mahjong(枚举+模拟)(2012 Asia Tianjin Regional Contest)

    Problem Description Japanese Mahjong is a four-player game. The game needs four people to sit around ...

随机推荐

  1. 前端路由原理及vue-router介绍

    前端路由原理本质就是监听 URL 的变化,然后匹配路由规则,显示相应的页面,并且无须刷新.目前单页面使用的路由就只有两种实现方式 hash history www.test.com/##/ 就是 Ha ...

  2. leetcode笔记(五)809. Expressive Words

    题目描述 Sometimes people repeat letters to represent extra feeling, such as "hello" -> &qu ...

  3. VMware ESXi-6.7——使用

    1: 上传ISO文件 1.1:创建一个新目录,上传ISO 1.2: 在新建虚拟机时,点击DVD,选择数据ISO文件,选择要安装的ISO文件.并把连接打钩. 2:新建虚拟机 按照需求填写 硬盘的三种置备 ...

  4. mysql like 变量

    Mysql: select * from 表名 where 字段 like concat('%',变量,'%');  

  5. jquery图片滚动demo.css

    body, html { font-size: 100%; padding: 0; margin: 0;} /* Reset */*,*:after,*:before { -webkit-box-si ...

  6. Oracle数据库远程访问

    如果需要访问非本机的Oracle数据库,首先需要安装一个Oracle的客户端,我直接安装的服务器版本的Oracle,也自带客户端. 安装完成后,如果访问本机的服务器的话,直接就可以访问,无需配置, 如 ...

  7. 五、RegExp(正则表达式)篇

    正则表达式,只用记住: 0./pattern/igm   i--不区分大小写 g--找到所有相匹配的 m--多行匹配  可以只写其中一个  ps:/pattern/i (无视大小写) 1." ...

  8. Hadoop(17)-MapReduce框架原理-MapReduce流程,Shuffle机制,Partition分区

    MapReduce工作流程 1.准备待处理文件 2.job提交前生成一个处理规划 3.将切片信息job.split,配置信息job.xml和我们自己写的jar包交给yarn 4.yarn根据切片规划计 ...

  9. 8.1 编写USB鼠标驱动程序,并测试

    学习目标:编写USB鼠标驱动程序,并测试(将USB鼠标的左键当作L按键,将USB鼠标的右键当作S按键,中键当作回车按键). 一.怎么写USB设备驱动程序?步骤如下: 1. 首先先定义全局变量usb_d ...

  10. php安装php-redis扩展

    下载安装php-redis扩展: 地址:https://github.com/phpredis/phpredis/ $ wget http://pecl.php.net/get/redis-3.1.2 ...