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. 存储过程系列五:完整的存储过程备份使用函数REPLACE()substr()

    CREATE OR REPLACE PROCEDURE "YLQXSCXKESL_GGXKZ_TO_QB" (                                    ...

  2. dhclient命令

    语法:dhclient(选项)(参数) 选项0:指定dhcp客户但监听的端口号-d:总是以前台方式运行程序-q:安静模式,不打印任何错误的提示信息-r:释放ip地址 参数:网络接口:操作的网络接口 示 ...

  3. IntelliJ IDEA 2016.1注册码

    IntelliJ IDEA 2016.1刚发布不久,破解注册的方法是在太少,15的注册URL也不管用,真是很头疼... 幸好发现一枚注册码,感谢sanshi的奉献精神!!! 原文链接:    http ...

  4. Vue父子组件间的通信

    父组件通过 props 向下传递数据给子组件,子组件通过 events 向上给父组件发送消息. 父组件: <div> <div style="background:#344 ...

  5. python之yield和Generator

    首先我们从一个小程序导入,各定一个list,找出其中的素数,我们会这样写 import math def is_Prims(number): if number == 2: return True / ...

  6. Jmeter 在什么情况下定义多个thread group?

    Jmeter里面有三种线程组:setUp thread group, TearDown thread group, thread group. 如果想定义100个用户登录系统,60个用户做A操作,40 ...

  7. tyvj1940创世纪——贪心(基环树)

    题目:http://www.joyoi.cn/problem/tyvj-1940 基环树的样子,看了书上的讲解,准备写树上DP,然后挂了: #include<iostream> #incl ...

  8. bzoj4430

    bit+容斥原理 我不会cdq分治只能用这个做法 考虑什么情况下不满足,至少有一个顺序不对就不行了,那么不满足的总有两对属性形成逆序对,那么我们用总方案数*2=n*(n-1)减去不符合的*2再/2就是 ...

  9. 你忘记的java运算符

    当整数被0除时会得到一个无穷大,或者nan, 所以会抛出数据溢出的异常.

  10. NodeJS REST API with MySQL and Express

    http://www.nodewiz.biz/nodejs-rest-api-with-mysql-and-express/ NPM Modules Express felixge/node-mysq ...