FJNU 1154 Fat Brother And His Love(胖哥与女神)
FJNU 1154 Fat Brother And His Love(胖哥与女神)
Time Limit: 2000MS Memory Limit: 257792K
|
【Description】 |
【题目描述】 |
|
As we know, fat Brother and his goddess is in a same city. The city is consist of N locations and the N locations is connected by M roads. Fat Brother has a crush on his goddess, but when he knew that the goddess want to date with other boy, he is reluctant. So he decided to stop their dating, then he go to find a single giant bomb from the warehouse. He can use this giant bomb blew up a road. Fat Brother wondered whether he can separate goddess and other boy by blowing up a road. Fat Brother gives Q questions that each query is given two numbers u and v which means the number of the location of the goddess and the boy. If fat Brother can separate goddess and other boy, output a line “Hei!Hei!Hei!” and a line integer denoting the ways to separate them. If fat Brother can't, output a line “No! I choose to go die!”. You can think the city which Fat Brother, goddess and boys are in is an undirected graph, and the graph is always connected in the beginning. If you can't understand it, you should observate the sample Input and sample Output |
众所周知,胖哥与他的女神同城。这座城市有N个地方被M条路连接。胖哥迷恋着女神,当他知晓女神要和其他男生约会时,他是拒绝的。因此他决定去阻止这一切,接着他在仓库里找了个大炸弹。他可以用这个炸弹破坏一条路。胖哥想知道是否通过破坏一条路阻隔女神与其他男生。胖哥给出Q个问题,每个问题给定两个数u和v表示女神与其男生的位置。如果胖哥可以阻隔女神与其他男生,输出一行“Hei!Hei!Hei!”与一行整数表示将他们分开方式。否则输出一行“No! I choose to go die!”。 你可以认为胖哥所在的城市中,女神与男生在一个无向图中,并且开始时图都是连通的。 如果你还是不明觉厉,可以看看输入输出样例。 |
|
【Input】 |
【输入】 |
|
There are multiple test cases. The first line of input contains an integer T (T <= 25) indicating the number of test cases. For each test case: The first line contains three integer N, M and Q denoting there are N locations and M roads in the city. The Q denoting there are Q questions. (1 <= N <= 100000, 1 <= m <= 100000, 1 <= Q <= 100000) Each of the 2…M + 1 lines contains two integers u and v denoting there is a undirected road between u and v. Each of the M + 2 … M + 1 + Q lines contains two integer u and v denoting the fat Brother's question. |
多组测试用例。 第一行是一个整数T(T <= 25)表示测试用例的数量。对于每个测试用例: 第一行有三个数N, M与Q 表示这个城市有N个地方M条路。Q表示有Q个问题。(1 <= N <= 100000, 1 <= m <= 100000, 1 <= Q <= 100000) 第2…M + 1行每行有两个整数u和v表示u与v间有一条双向的路。 第M + 2 … M + 1 + Q行每行有两个整数u与v,表示胖哥的问题。 |
|
【Output】 |
【输出】 |
|
For each case, output according to Title Description. |
对于每个用例,输出题目描述要求的结果。 |
|
【Sample Input - 输入样例】 |
【Sample Output - 输出样例】 |
|
2 9 11 19 1 2 1 3 2 3 2 4 4 5 4 6 5 6 6 7 7 8 7 9 8 9 1 2 1 3 2 3 2 4 4 5 4 6 5 6 6 7 7 8 7 9 8 9 1 4 4 7 8 5 3 6 9 4 1 6 7 3 2 9 10 9 8 1 2 1 3 3 4 4 5 3 6 6 7 3 8 8 9 8 10 1 5 1 2 7 5 9 4 2 3 6 2 4 1 3 9 |
No! I choose to go die! No! I choose to go die! No! I choose to go die! Hei!Hei!Hei! 1 No! I choose to go die! No! I choose to go die! No! I choose to go die! Hei!Hei!Hei! 1 No! I choose to go die! No! I choose to go die! No! I choose to go die! Hei!Hei!Hei! 1 Hei!Hei!Hei! 1 Hei!Hei!Hei! 1 Hei!Hei!Hei! 1 Hei!Hei!Hei! 1 Hei!Hei!Hei! 1 Hei!Hei!Hei! 2 Hei!Hei!Hei! 2 Hei!Hei!Hei! 3 Hei!Hei!Hei! 1 Hei!Hei!Hei! 4 Hei!Hei!Hei! 3 Hei!Hei!Hei! 2 Hei!Hei!Hei! 3 Hei!Hei!Hei! 2 Hei!Hei!Hei! 2 |
【题解】
2016.10.30补:此代码在
1
3 2 1
1 3
3 2
1 3
时存在问题,测试数据的给出方式似乎恰好回避了访问乱序
实际中的缩点算法存在漏洞,待更新(加个数组就好了,懒癌发作,有空再补)……
题目的大意就是在连通的无向图里面找割边的数量。
大体步骤:①缩点(合并环)Tarjan算法 ②建立多叉树 ③查询
Tarjan算法:百度一下(反正我也看不懂,直接看代码的)
建立多叉树:因为环都没有了,因此图就变成一颗多叉树了
查询:
暴力搜索:因为目测暴力搜索会超时,所以就没去试了(懒癌发作)
树链剖分:根据某人表示可以用,然而本渣并不能看懂……
所以我就看着树链剖分的那幅图,自己琢磨着把树用部分转数组的方式加快

从1开始,把其中一个分枝加入读取行的数组,其他分枝都加入到下一行的数组中去。保存每个元素第一次出现的位置,每次跳转到当前数组开头只需要O(1),晚建立的层不断向早建立的层调整,可以快速(大雾)得到公共父节点,并且在执行的时候把经过的边数累计,就可以得到割边数量了。
【代码 C++】
#include<cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define mx 100005 struct edge {
int to, next;
}Edge[mx], EdgeOLD[mx << ];
int Head[mx], iE, iE_OLD, ID[mx];
int Stack[mx], iS = ;
bool inUS[mx];
void addEdgeOLD(int u, int v) {
EdgeOLD[iE_OLD].next = Head[u]; EdgeOLD[iE_OLD].to = v;
Head[u] = iE_OLD++;
}
void addEdge(int u, int v) {
Edge[iE].next = Head[u]; Edge[iE].to = v;
Head[u] = iE++;
} void DFS_Tarjan(int now, int anti) {//(当前节点, 反向边)
ID[now] = Stack[++iS] = now;
inUS[now] = ;
int u, v, i = iS;
for (u = Head[now]; ~u; u = EdgeOLD[u].next) {
if (u == anti) continue;
v = EdgeOLD[u].to;
if (!inUS[v]) DFS_Tarjan(v, u ^ );
ID[now] = std::min(ID[now], ID[v]);
}
if (Stack[i] == ID[now]) {
while (i <= iS) {
inUS[Stack[iS]] = ;
ID[Stack[iS--]] = ID[now];
}
}
}
void markID() {
iS = ;
memset(inUS, , sizeof(inUS));
DFS_Tarjan(, -);
} std::vector<int> listTree[mx];
struct Point {
int y, x;
}PointAddress[mx];
void BFS() {
int u, v, y, x, now;
bool fst = ;
std::queue<Point> q;
q.push({ iS = , });
PointAddress[] = { , };
listTree[].push_back();
++inUS[]; while (!q.empty()) {
y = q.front().y; x = q.front().x;
now = listTree[y][x]; q.pop();
fst = ; for (u = Head[now]; ~u; u = Edge[u].next) {
v = Edge[u].to;
if (inUS[v]) continue;
++inUS[v];
if (!fst) {//加入当前行
q.push(PointAddress[v] = { y, listTree[y].size() });
listTree[y].push_back(v); ++fst;
}
else {//加入新一行
listTree[++iS].push_back(now);
q.push(PointAddress[v] = { iS, listTree[iS].size() });
listTree[iS].push_back(v);
}
}
}
}
void buildAddress(int n) {
iE = ;
int HeadOLD[mx], i, u, v;
memcpy(HeadOLD, Head, sizeof(Head));
memset(Head, -, sizeof(Head));
for (i = ; i <= n; ++i) {//建立多叉树
for (u = HeadOLD[i]; ~u; u = EdgeOLD[u].next) {
v = EdgeOLD[u].to;
if (ID[i] < ID[v]) addEdge(ID[i], ID[v]);
}
} for (i = ; i < mx; ++i) listTree[i].clear();
BFS();//将各个节点加入数组
} int fid(Point u, Point v) {
int opt = , to;
Point temp;
while (u.y != v.y) {//未跳转到同一行时进行跳转,并记录经过边的数量。
if (u.y < v.y) { temp = v; v = u; u = temp; }
opt += u.x;
to = listTree[u.y][];
u = PointAddress[to];
}
if (u.x < v.x) { u.x ^= v.x; v.x ^= u.x; u.x ^= v.x; }
return opt + u.x - v.x;
} int main() {
int t, n, m, q, i, u, v;
while (~scanf("%d", &t)) {
while (t--) {
memset(Head, -, sizeof(Head)); iE_OLD = ;
scanf("%d%d%d", &n, &m, &q);
for (i = ; i < m; ++i) {
scanf("%d%d", &u, &v);
addEdgeOLD(u, v); addEdgeOLD(v, u);
}
markID();//对各个顶点进行再编号
buildAddress(n);//建立各顶点的地址
for (i = ; i < q; ++i) {
scanf("%d%d", &u, &v);
u = ID[u]; v = ID[v];
if (u == v) puts("No! I choose to go die!");
else {
puts("Hei!Hei!Hei!");
printf("%d\n", fid(PointAddress[u], PointAddress[v]));
}
}
}
}
return ;
}
FJNU 1154
#include<cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define mx 100005
int readInt() {
int add = getchar() - '';
for (char a = getchar(); a >= '' && a <= ''; a = getchar()) {
add = add * + a - '';
}
return add;
} struct edge {
int to, next;
}Edge[mx], EdgeOLD[mx << ];
int Head[mx], iE, iE_OLD, ID[mx], HeadA[mx];
int Stack[mx], iS = ;
bool inUS[mx];
void addEdgeOLD(int u, int v) {
EdgeOLD[iE_OLD].next = Head[u]; EdgeOLD[iE_OLD].to = v;
Head[u] = iE_OLD++;
}
void addEdge(int u, int v) {
Edge[iE].next = Head[u]; Edge[iE].to = v;
Head[u] = iE++;
} void DFS_Tarjan(int now, int anti) {//(当前节点, 反向边)
ID[now] = Stack[++iS] = now;
inUS[now] = ;
int u, v, i = iS;
for (u = Head[now]; ~u; u = EdgeOLD[u].next) {
if (u == anti) continue;
v = EdgeOLD[u].to;
if (!inUS[v]) DFS_Tarjan(v, u ^ );
ID[now] = std::min(ID[now], ID[v]);
}
if (Stack[i] == ID[now]) {
while (i <= iS) {
inUS[Stack[iS]] = ;
ID[Stack[iS--]] = ID[now];
}
}
}
void markID() {
iS = ;
memset(inUS, , sizeof(inUS));
DFS_Tarjan(, -);
} struct Point {
int y, x, data;
}PointAddress[mx];
void BFS() {
int u, v, y, x, now, HeadASize[mx];
memset(HeadASize, , sizeof(HeadASize));
bool fst = ;
std::queue<Point> q;
q.push({ iS = , , });
PointAddress[] = { , , };
HeadA[] = ; ++HeadASize[];
++inUS[]; while (!q.empty()) {
y = q.front().y; x = q.front().x; now = q.front().data;
q.pop();
fst = ; for (u = Head[now]; ~u; u = Edge[u].next) {
v = Edge[u].to;
if (inUS[v]) continue;
++inUS[v];
if (fst) {//加入当前行
q.push(PointAddress[v] = { y, HeadASize[y]++, v });
fst = ;
}
else {//加入新一行
HeadA[++iS] = now; ++HeadASize[iS];
q.push(PointAddress[v] = { iS, HeadASize[iS]++, v });
}
}
}
}
void buildAddress(int n) {
iE = ;
int HeadOLD[mx], i, u, v;
memcpy(HeadOLD, Head, sizeof(Head));
memset(Head, -, sizeof(Head));
for (i = ; i <= n; ++i) {//建立多叉树
for (u = HeadOLD[i]; ~u; u = EdgeOLD[u].next) {
v = EdgeOLD[u].to;
if (ID[i] < ID[v]) addEdge(ID[i], ID[v]);
}
} BFS();//将各个节点加入数组
}
int fid(Point u, Point v) {
int opt = ;
Point temp;
while (u.y != v.y) {//未跳转到同一行时进行跳转,并记录经过边的数量。
if (u.y < v.y) { temp = v; v = u; u = temp; }
opt += u.x;
u = PointAddress[HeadA[u.y]];
}
if (u.x < v.x) { u.x ^= v.x; v.x ^= u.x; u.x ^= v.x; }
return opt + u.x - v.x;
}
int main() {
int t, n, m, q, i, u, v;
while (t = readInt(), t>) {
while (t--) {
memset(Head, -, sizeof(Head)); iE_OLD = ;
n = readInt(); m = readInt(); q = readInt();
for (i = ; i < m; ++i) {
u = readInt(); v = readInt();
addEdgeOLD(u, v); addEdgeOLD(v, u);
}
markID();//对各个顶点进行再编号
buildAddress(n);//建立各顶点的地址
for (i = ; i < q; ++i) {
u = ID[readInt()]; v = ID[readInt()];
if (u == v) puts("No! I choose to go die!");
else {
puts("Hei!Hei!Hei!");
printf("%d\n", fid(PointAddress[u], PointAddress[v]));
}
}
}
}
return ;
}
【后记】
由于不同平台对栈内存的分配不同,在windows默认1MB的情况下某些数据会出现爆栈的情况(OJ上是linux系统),自己可以提高栈内存的大小。
FJNU 1154 Fat Brother And His Love(胖哥与女神)的更多相关文章
- FJNU 1153 Fat Brother And XOR(胖哥与异或)
FJNU 1153 Fat Brother And XOR(胖哥与异或) Time Limit: 1000MS Memory Limit: 257792K [Description] [题目描述] ...
- FJNU 1155 Fat Brother’s prediction(胖哥的预言)
FJNU 1155 Fat Brother’s prediction(胖哥的预言) Time Limit: 1000MS Memory Limit: 257792K [Description] [ ...
- FJNU 1152 Fat Brother And Integer(胖哥与整数)
FJNU 1152 Fat Brother And Integer(胖哥与整数) Time Limit: 1000MS Memory Limit: 257792K [Description] [题 ...
- FJNU 1156 Fat Brother’s Gorehowl(胖哥的血吼)
FJNU 1156 Fat Brother’s Gorehowl(胖哥的血吼) Time Limit: 1000MS Memory Limit: 257792K [Description] [题目 ...
- FJNU 1151 Fat Brother And Geometry(胖哥与几何)
FJNU 1151 Fat Brother And Geometry(胖哥与几何) Time Limit: 1000MS Memory Limit: 257792K [Description] [ ...
- FJNU 1157 Fat Brother’s ruozhi magic(胖哥的弱智术)
FJNU 1157 Fat Brother’s ruozhi magic(胖哥的弱智术) Time Limit: 1000MS Memory Limit: 257792K [Description ...
- FJNU 1159 Fat Brother’s new way(胖哥的新姿势)
FJNU 1159 Fat Brother’s new way(胖哥的新姿势) Time Limit: 1000MS Memory Limit: 257792K [Description] [题目 ...
- HDU 4637 Rain on your Fat brother 线段与半圆和线段交 简单题
题意: 应该不难读懂. 做法: 我们可以把雨滴看做静止不动,然后maze(这题的那个人)就是往左上方运动就可以了,计算出maze能跑到的最远的点,然后就是求起点和终点所构成的线段与每个雨滴交的时间,注 ...
- 大数据的胖哥的方式(9)- 金融业数据仓库的逻辑模型FS-LDM
介绍: 大数据是不是海市蜃楼,来自小橡子只是意淫奥克斯,大数据的发展,而且要从头开始,基于大数据建设国家.项目-level数据中心行业将越来越多,大数据仅供技术,而非溶液,临数据组织模式,数据逻辑模式 ...
随机推荐
- uploadify3.2.1加载时,报NetworkError 404 Not Found或NetworkError forbidden错误
我用的uploadify的版本是3.2.1 在打开配置了uploadify的页面的时候,什么操作都没有,仅仅是打开了页面,在火狐里可以看到一行报错信息,我的uploadify页面 在"/项目 ...
- cpu进程调度---RT Throttling【转】
转自:http://book.2cto.com/201302/16291.html RT Throttling是对分配给实时进程的CPU时间进行限制的功能.使用实时调度策略的进程由于bug等出现不可控 ...
- PHP处理CSV表格文件的常用操作方法是怎么样呢
php来说,fgetcsv读入csv表格,返回一个数组,然后foreach输出成HTML的<table>,这步操作几行代码就能实现,非常简单.工作量主要还在于浏览器前端,建议你用jQuer ...
- PHP序列化以及反序列化系列[1]--PHP序列化格式的写法
反序列化:对单一的已序列化的变量进行操作,将其转换回 PHP 的值(zval). PHP序列化方式 PHP在序列化的时候会将相应的变量以对应的键值进行储存. 将一个类序列化的话,处理代码主要的 文件: ...
- POJ 2763:Housewife Wind(树链剖分)
http://poj.org/problem?id=2763 题意:给出 n 个点, n-1 条带权边, 询问是询问 s 到 v 的权值, 修改是修改存储时候的第 i 条边的权值. 思路:树链剖分之修 ...
- windows7 安装 memcached
下载 memcached 的 windows 稳定 memcached.exe 版本,然后解压到某个目录下面,这里放到了 D:\ApacheServer\memcached 找到 C:\Windows ...
- Bellman-Ford 算法及其优化
Bellman-Ford 算法及其优化 转自:http://hi.baidu.com/jzlikewei/blog/item/94db7950f96f995a1038c2cd.html Bellman ...
- Python学习笔记-Day2-Python基础之列表操作
列表的常用操作包括但不限于以下操作: 列表的索引,切片,追加,删除,切片等 这里将对列表的内置操作方法进行总结归纳,重点是以示例的方式进行展示. 使用type获取创建对象的类 type(list) 使 ...
- sqlserver2008安装教程
这几天因为需要,一直想安装sql server 2008来作为Web后台的数据库进行些实验,但总是没有时间,今天终于有时间了,便安装了SQL Server 2008,以下是我的安装的步骤,希望对于有需 ...
- linux(centos6.5 i386)安装mysql5.6源码包
在开始安装前,先说明一下mysql-5.6.4与较低的版本在安装上的区别,从mysql-5.5起,mysql源码安装开始使用cmake了,因此当我们配置安装目录./configure --perfix ...