http://acm.hdu.edu.cn/showproblem.php?pid=3686

我要把这题记录下来。

一直wa。

自己生成数据都是AC的。现在还是wa。留坑。

我感觉我现在倒下去床上就能睡着了。

不知道是我的LCA错了,还是tarjan

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxm = + ;
const int maxn = + ;
struct Edge {
int u, v, id, tonext;
} e[maxm * ];
int first[maxm], num;
void addEdge(int u, int v, int id) {
++num;
e[num].u = u, e[num].v = v, e[num].tonext = first[u];
first[u] = num;
e[num].id = id;
}
int uuu[maxm], vvv[maxm];
int n, m;
int low[maxm], DFN[maxm], st[maxm], id[maxm];
int top, when, toSelid;
bool iscut[maxm];
vector<int>bolg[maxm];
int root;
void tarjan(int cur, int fa) {
DFN[cur] = low[cur] = ++when;
int child = ;
for (int i = first[cur]; i; i = e[i].tonext) {
int v = e[i].v;
if (v == fa) continue;
if (!DFN[v]) {
child++;
st[++top] = e[i].id;
tarjan(v, cur);
low[cur] = min(low[cur], low[v]);
if (low[v] >= DFN[cur]) {
iscut[cur] = true;
// if (cur == root && child < 2) iscut[cur] = false;
++toSelid;
do {
int eID = st[top--];
bolg[uuu[eID]].push_back(toSelid);
bolg[vvv[eID]].push_back(toSelid);
id[eID] = toSelid;
} while (st[top + ] != e[i].id);
} } else if (DFN[cur] > DFN[v]) {
low[cur] = min(low[cur], DFN[v]);
st[++top] = e[i].id;
}
}
}
void solveTarjan(int n) {
memset(DFN, , sizeof DFN);
memset(low, , sizeof low);
memset(iscut, , sizeof iscut);
memset(id, , sizeof id);
for (int i = ; i <= maxm - ; ++i) {
bolg[i].clear();
}
when = top = toSelid = ;
for (int i = ; i <= n; ++i) {
if (!DFN[i]) {
root = i;
tarjan(i, i);
}
}
}
int dis[maxm];
bool treeCut[maxm], vis[maxm];
struct Node {
int cur, cnt;
Node(int _cur, int _cnt) {
cur = _cur, cnt = _cnt;
}
};
void bfs(int be) {
vis[be] = true;
dis[be] = treeCut[be];
queue<struct Node>que;
que.push(Node(be, treeCut[be]));
while (!que.empty()) {
struct Node t = que.front();
que.pop();
for (int i = first[t.cur]; i; i = e[i].tonext) {
int v = e[i].v;
if (vis[v]) continue;
vis[v] = true;
dis[v] = t.cnt + treeCut[v];
que.push(Node(v, t.cnt + treeCut[v]));
}
}
}
int ansc[maxn * ][], deep[maxm], fa[maxm];
void init_LCA(int cur) {
ansc[cur][] = fa[cur]; //跳1步,那么祖先就是爸爸
for (int i = ; i <= ; ++i) { //倍增思路,递归处理
ansc[cur][i] = ansc[ansc[cur][i - ]][i - ];
}
for (int i = first[cur]; i; i = e[i].tonext) {
int v = e[i].v;
if (v == fa[cur]) continue;
fa[v] = cur;
deep[v] = deep[cur] + ;
init_LCA(v);
}
}
int LCA(int x, int y) {
if (deep[x] < deep[y]) swap(x, y); //需要x是最深的
for (int i = ; i >= ; --i) { //从大到小枚举,因为小的更灵活
if (deep[ansc[x][i]] >= deep[y]) { //深度相同,走进去就对了。就是要去到相等。
x = ansc[x][i];
}
}
if (x == y) return x;
for (int i = ; i >= ; --i) {
if (ansc[x][i] != ansc[y][i]) { //走到第一个不等的地方,
x = ansc[x][i];
y = ansc[y][i];
}
}
return ansc[x][]; //再跳一步就是答案
}
void init() {
num = ;
memset(ansc, , sizeof ansc);
memset(deep, , sizeof deep);
memset(fa, , sizeof fa);
memset(dis, , sizeof dis);
memset(treeCut, , sizeof treeCut);
memset(vis, , sizeof vis); }
void work() {
init();
num = ;
memset(first, , sizeof first);
for (int i = ; i <= m; ++i) {
int u, v;
scanf("%d%d", &u, &v);
addEdge(u, v, i);
addEdge(v, u, i);
uuu[i] = u;
vvv[i] = v;
}
solveTarjan(n);
memset(first, , sizeof first);
memset(treeCut, , sizeof treeCut);
num = ;
int to = toSelid;
for (int i = ; i <= n; ++i) {
if (!iscut[i]) continue;
++to;
treeCut[to] = true;
sort(bolg[i].begin(), bolg[i].end());
addEdge(to, bolg[i][], );
addEdge(bolg[i][], to, );
for (int j = ; j < bolg[i].size(); ++j) {
if (bolg[i][j - ] == bolg[i][j]) continue;
addEdge(to, bolg[i][j], );
addEdge(bolg[i][j], to, );
}
}
// int tot = 2;
// for (int i = 0; i < bolg[tot].size(); ++i) {
// cout << bolg[tot][i] << " ";
// }
// cout << endl;
memset(vis, false, sizeof vis);
memset(fa, , sizeof fa);
memset(deep, , sizeof deep);
memset(ansc, , sizeof ansc);
memset(dis, , sizeof dis);
for (int i = ; i <= to; ++i) {
if (vis[i]) continue;
bfs(i);
fa[i] = i;
deep[i] = ;
init_LCA(i);
}
// cout << iscut[11] << " ***" << endl;
int q;
scanf("%d", &q);
while (q--) {
int x, y;
scanf("%d%d", &x, &y);
x = id[x];
y = id[y];
if (x == y) {
printf("0\n");
continue;
}
int res = LCA(x, y);
if (res == x) {
assert(treeCut[x] == );
}
if (res == y) {
assert(treeCut[y] == );
}
int ans = dis[x] + dis[y] - * dis[res];
assert(ans + treeCut[res] >= );
printf("%d\n", ans + treeCut[res]);
}
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
while (scanf("%d%d", &n, &m) != EOF && (n + m)) work();
return ;
}

原来这题是有重边的,怪不得我一直wa。而且自己生成的数据都是没有重边的,TAT

说下思路,

题目要求的经过多少个割点,

首先,题目给出的是从边s走到边t。这样很好办,一开始以为是点s做到点t,这样比较麻烦。

先做一次点双连通分量,对边分好id。然后对于每一个割点,把和它连接的边重建一颗树。然后这个割点就是这棵树的treeCut

这就相当于给出一颗树,树上有些点(那副图的边变成点了)是染色了的,问从点s走到点t,最少走过多少个染色的点。

这样可以预处理出dis[i]表示从树根走到点i,一共经过多少个染色的点,这样就相当于区间减法,然后配合lca即可。

1、题目虽然保证roads到rodat有路,但是可能有多个连通分支。

2、有重边。

其实有重边不用怕,没什么的,只需要标记那条边是用过了的就可以。

既可以判断不返回fa,又可以判重边。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxm = + ;
const int maxn = + ;
struct Edge {
int u, v, id, tonext;
} e[maxm * ];
int first[maxm], num;
void addEdge(int u, int v, int id) {
++num;
e[num].u = u, e[num].v = v, e[num].tonext = first[u];
first[u] = num;
e[num].id = id;
}
int uuu[maxm], vvv[maxm];
int n, m;
int low[maxm], DFN[maxm], st[maxm], id[maxm];
int top, when, toSelid;
bool iscut[maxm];
vector<int>bolg[maxm];
int root;
void tarjan(int cur, int fa, int fromID) {
DFN[cur] = low[cur] = ++when;
int child = ;
for (int i = first[cur]; i; i = e[i].tonext) {
int v = e[i].v;
if (v == fa && e[i].id == fromID) continue;
if (!DFN[v]) {
child++;
st[++top] = e[i].id;
tarjan(v, cur, e[i].id);
low[cur] = min(low[cur], low[v]);
if (low[v] >= DFN[cur]) {
iscut[cur] = true;
// if (cur == root && child < 2) iscut[cur] = false;
++toSelid;
do {
int eID = st[top--];
bolg[uuu[eID]].push_back(toSelid);
bolg[vvv[eID]].push_back(toSelid);
id[eID] = toSelid;
} while (st[top + ] != e[i].id);
} } else if (DFN[cur] > DFN[v]) {
low[cur] = min(low[cur], DFN[v]);
st[++top] = e[i].id;
}
}
}
void solveTarjan(int n) {
memset(DFN, , sizeof DFN);
memset(low, , sizeof low);
memset(iscut, , sizeof iscut);
memset(id, , sizeof id);
for (int i = ; i <= maxm - ; ++i) {
bolg[i].clear();
}
when = top = toSelid = ;
for (int i = ; i <= n; ++i) {
if (!DFN[i]) {
root = i;
tarjan(i, i, -);
}
}
}
int dis[maxm];
bool treeCut[maxm], vis[maxm];
struct Node {
int cur, cnt;
Node(int _cur, int _cnt) {
cur = _cur, cnt = _cnt;
}
};
void bfs(int be) {
vis[be] = true;
dis[be] = treeCut[be];
queue<struct Node>que;
que.push(Node(be, treeCut[be]));
while (!que.empty()) {
struct Node t = que.front();
que.pop();
for (int i = first[t.cur]; i; i = e[i].tonext) {
int v = e[i].v;
if (vis[v]) continue;
vis[v] = true;
dis[v] = t.cnt + treeCut[v];
que.push(Node(v, t.cnt + treeCut[v]));
}
}
}
int ansc[maxn * ][], deep[maxm], fa[maxm];
void init_LCA(int cur) {
ansc[cur][] = fa[cur]; //跳1步,那么祖先就是爸爸
for (int i = ; i <= ; ++i) { //倍增思路,递归处理
ansc[cur][i] = ansc[ansc[cur][i - ]][i - ];
}
for (int i = first[cur]; i; i = e[i].tonext) {
int v = e[i].v;
if (v == fa[cur]) continue;
fa[v] = cur;
deep[v] = deep[cur] + ;
init_LCA(v);
}
}
int LCA(int x, int y) {
if (deep[x] < deep[y]) swap(x, y); //需要x是最深的
for (int i = ; i >= ; --i) { //从大到小枚举,因为小的更灵活
if (deep[ansc[x][i]] >= deep[y]) { //深度相同,走进去就对了。就是要去到相等。
x = ansc[x][i];
}
}
if (x == y) return x;
for (int i = ; i >= ; --i) {
if (ansc[x][i] != ansc[y][i]) { //走到第一个不等的地方,
x = ansc[x][i];
y = ansc[y][i];
}
}
return ansc[x][]; //再跳一步就是答案
}
void work() {
num = ;
memset(first, , sizeof first);
for (int i = ; i <= m; ++i) {
int u, v;
scanf("%d%d", &u, &v);
addEdge(u, v, i);
addEdge(v, u, i);
uuu[i] = u;
vvv[i] = v;
}
solveTarjan(n);
memset(first, , sizeof first);
memset(treeCut, , sizeof treeCut);
num = ;
int to = toSelid;
for (int i = ; i <= n; ++i) {
if (!iscut[i]) continue;
++to;
treeCut[to] = true;
sort(bolg[i].begin(), bolg[i].end());
addEdge(to, bolg[i][], );
addEdge(bolg[i][], to, );
for (int j = ; j < bolg[i].size(); ++j) {
if (bolg[i][j - ] == bolg[i][j]) continue;
addEdge(to, bolg[i][j], );
addEdge(bolg[i][j], to, );
}
}
// int tot = 2;
// for (int i = 0; i < bolg[tot].size(); ++i) {
// cout << bolg[tot][i] << " ";
// }
// cout << endl;
memset(vis, false, sizeof vis);
for (int i = ; i <= to; ++i) {
if (vis[i]) continue;
bfs(i);
fa[i] = i;
deep[i] = ;
init_LCA(i);
}
// cout << iscut[11] << " ***" << endl;
int q;
scanf("%d", &q);
while (q--) {
int x, y;
scanf("%d%d", &x, &y);
x = id[x];
y = id[y];
if (x == y) {
printf("0\n");
continue;
}
int res = LCA(x, y);
if (res == x) {
assert(treeCut[x] == );
}
if (res == y) {
assert(treeCut[y] == );
}
int ans = dis[x] + dis[y] - * dis[res];
assert(ans + treeCut[res] >= );
printf("%d\n", ans + treeCut[res]);
}
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
while (scanf("%d%d", &n, &m) != EOF && (n + m)) work();
return ;
}

代码写的很烂,因为wa了3小时,一直在yy改错。

hdu 3686 Traffic Real Time Query System 点双两通分量 + LCA。这题有重边!!!的更多相关文章

  1. HDU 3686 Traffic Real Time Query System(双连通分量缩点+LCA)(2010 Asia Hangzhou Regional Contest)

    Problem Description City C is really a nightmare of all drivers for its traffic jams. To solve the t ...

  2. HDU 3686 Traffic Real Time Query System (图论)

    HDU 3686 Traffic Real Time Query System 题目大意 给一个N个点M条边的无向图,然后有Q个询问X,Y,问第X边到第Y边必需要经过的点有多少个. solution ...

  3. HDU 3686 Traffic Real Time Query System(点双连通)

    题意 ​ 给定一张 \(n\) 个点 \(m\) 条边的无向图,\(q\) 次询问,每次询问两边之间的必经之点个数. 思路 ​ 求两点之间必经之边的个数用的是边双缩点,再求树上距离.而对比边双和点双之 ...

  4. 【HDOJ】3686 Traffic Real Time Query System

    这题做了几个小时,基本思路肯定是求两点路径中的割点数目,思路是tarjan缩点,然后以割点和连通块作为新节点见图.转化为lca求解.结合点——双连通分量与LCA. /* 3686 */ #includ ...

  5. 【Targan+LCA】HDU 3686 Traffic Real Time Query

    题目内容 洛谷链接 给出一个\(n\)个节点,\(m\)条边的无向图和两个节点\(s\)和\(t\),问这两个节点的路径中有几个点必须经过. 输入格式 第一行是\(n\)和\(m\). 接下来\(m\ ...

  6. CH#24C 逃不掉的路 和 HDU3686 Traffic Real Time Query System

    逃不掉的路 CH Round #24 - 三体杯 Round #1 题目描述 现代社会,路是必不可少的.任意两个城镇都有路相连,而且往往不止一条.但有些路连年被各种XXOO,走着很不爽.按理说条条大路 ...

  7. HDU3686 Traffic Real Time Query System 题解

    题目 City C is really a nightmare of all drivers for its traffic jams. To solve the traffic problem, t ...

  8. Traffic Real Time Query System 圆方树+LCA

    题目描述 City C is really a nightmare of all drivers for its traffic jams. To solve the traffic problem, ...

  9. Traffic Real Time Query System HDU - 3686

    https://vjudge.net/problem/HDU-3686 点双啊,就是在求割顶的时候,另外用一个栈来存一些边 在遍历u点出发的边时,遇到树边或反向边(u,v)就把此边加入栈(可能要记一下 ...

随机推荐

  1. SpringMVC与Struts2区别与比较

    1.Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上Spr ...

  2. 查看系统信息,区分Centos和Ubuntu

    查看系统信息,区分Centos和Ubuntu # cat /etc/issue \S Kernel \r on an \m centos $ cat /etc/issue Ubuntu 16.04.4 ...

  3. codeforces B. Polo the Penguin and Matrix 解题报告

    题目链接:http://codeforces.com/problemset/problem/289/B 题目意思:给出一个 n 行 m 列的矩阵和数值 d .通过对矩阵里面的数进行 + d 或者 - ...

  4. powershell 扩展 (PSCX) 安装指南

    在玩ansible的过程中,使用win_unzip模块时powershell支持不了,需要安装PSCX对powershell进行扩展,随手记录下安装过程. 从官网下载的Pscx是一个zip压缩文件,解 ...

  5. easyui-tabs 在ie8下基于iframe嵌套页面加载成功后切换空白问题

    这是一个很坑的问题,由于项目必须支持ie8的情况下,产生了这个问题.在我进行逐步对比的分析过后,终于发现了原因所在:

  6. 51Nod - 1295:XOR key (可持久化Trie求区间最大异或)

    给出一个长度为N的正整数数组A,再给出Q个查询,每个查询包括3个数,L, R, X (L <= R).求ALL 至 ARR 这R - L + 1个数中,与X 进行异或运算(Xor),得到的最大值 ...

  7. POJ 2970 The lazy programmer(贪心+单调优先队列)

    A new web-design studio, called SMART (Simply Masters of ART), employs two people. The first one is ...

  8. 无向图hash

    一个效果还行的 无向图hash判同构的方法 求出每个点向其它点的最短路,然后排序,然后按字符串拼接起来,再按每个点的字符串 排序后的rank 作为每一个点的初始hash值 然后每一轮,把每个点的相邻点 ...

  9. linux 查看某进程 并杀死进程 ps grep kill

    Linux 中使用top 或 ps 查看进程使用kill杀死进程 1.使用top查看进程: $top 进行执行如上命令即可查看top!但是难点在如何以进程的cpu占用量进行排序呢? cpu占用量排序执 ...

  10. Nwjs简单配置

    1.创建一个工程,配置一个  package.json 文件 { "name": "application-name", "version" ...