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. 跟我一起学wpf(1)-布局

    wpf常用的布局控件 Canvas,DockPanel,Grid,StackPanel,WrapPane 1 Canvas是常用的画布容器,里面可以包含多个比如之前我写的3D效果的动画,都是用Canv ...

  2. Java网络编程InetAddress类

    InetAddress用来代表IP地址.一个InetAdress的对象就代表着一个IP地址, getByName(String host):在给定主机名的情况下确定主机的 IP 地址,主机名可以是机器 ...

  3. git学习笔记(上)

    1 安装 win安装 地址 安装之后自报家门 $ git config --global user.name "Your Name" $ git config --global u ...

  4. 洛谷P3385判负环——spfa

    题目:https://www.luogu.org/problemnew/show/P3385 两种方法,dfs和bfs: 一开始写的dfs,要把dis数组初值赋成0,这样从一个连着负边的点开始搜: 在 ...

  5. [转]git merge 跟 git merge -no-ff

    根据这张图片可以看出 git merge –no-ff 可以保存你之前的分支历史.能够更好的查看 merge历史,以及branch 状态. git merge 则不会显示 feature,只保留单条分 ...

  6. 爬虫库之BeautifulSoup学习(二)

    BeautifulSoup官方介绍文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html 四大对象种类: Beau ...

  7. HDU-2616

    Kill the monster Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  8. codevs-1205

    1205 单词翻转 题目描述 Description 给出一个英语句子,希望你把句子里的单词顺序都翻转过来 输入描述 Input Description 输入包括一个英语句子. 输出描述 Output ...

  9. 单例模式-Lazy initialization holder class模式

    这个模式综合使用了Java的类级内部类和多线程缺省同步锁的知识,很巧妙地同时实现了延迟加载和线程安全. 1.相应的基础知识 什么是类级内部类? 简单点说,类级内部类指的是,有static修饰的成员式内 ...

  10. ElasticSearch入门及核心概念介绍

      Elasticsearch研究有一段时间了,现特将Elasticsearch相关核心知识和原理以初学者的角度记录下来,如有不当,烦请指正! 0. 带着问题上路——ES是如何产生的? (1)思考:大 ...