hdu 3686 Traffic Real Time Query System 点双两通分量 + LCA

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 = 200000 + 20;
const int maxn = 10000 + 20;
struct Edge {
    int u, v, id, tonext;
} e[maxm * 2];
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 = 0;
    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 + 1] != 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, 0, sizeof DFN);
    memset(low, 0, sizeof low);
    memset(iscut, 0, sizeof iscut);
    memset(id, 0, sizeof id);
    for (int i = 1; i <= maxm - 2; ++i) {
        bolg[i].clear();
    }
    when = top = toSelid = 0;
    for (int i = 1; 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 * 4][22], deep[maxm], fa[maxm];
void init_LCA(int cur) {
    ansc[cur][0] = fa[cur]; //跳1步,那么祖先就是爸爸
    for (int i = 1; i <= 20; ++i) { //倍增思路,递归处理
        ansc[cur][i] = ansc[ansc[cur][i - 1]][i - 1];
    }
    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] + 1;
        init_LCA(v);
    }
}
int LCA(int x, int y) {
    if (deep[x] < deep[y]) swap(x, y); //需要x是最深的
    for (int i = 20; i >= 0; --i) { //从大到小枚举,因为小的更灵活
        if (deep[ansc[x][i]] >= deep[y]) { //深度相同,走进去就对了。就是要去到相等。
            x = ansc[x][i];
        }
    }
    if (x == y) return x;
    for (int i = 20; i >= 0; --i) {
        if (ansc[x][i] != ansc[y][i]) { //走到第一个不等的地方,
            x = ansc[x][i];
            y = ansc[y][i];
        }
    }
    return ansc[x][0]; //再跳一步就是答案
}
void init() {
    num = 0;
    memset(ansc, 0, sizeof ansc);
    memset(deep, 0, sizeof deep);
    memset(fa, 0, sizeof fa);
    memset(dis, 0, sizeof dis);
    memset(treeCut, 0, sizeof treeCut);
    memset(vis, 0, sizeof vis);

}
void work() {
    init();
    num = 0;
    memset(first, 0, sizeof first);
    for (int i = 1; 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, 0, sizeof first);
    memset(treeCut, 0, sizeof treeCut);
    num = 0;
    int to = toSelid;
    for (int i = 1; i <= n; ++i) {
        if (!iscut[i]) continue;
        ++to;
        treeCut[to] = true;
        sort(bolg[i].begin(), bolg[i].end());
        addEdge(to, bolg[i][0], 1);
        addEdge(bolg[i][0], to, 1);
        for (int j = 1; j < bolg[i].size(); ++j) {
            if (bolg[i][j - 1] == bolg[i][j]) continue;
            addEdge(to, bolg[i][j], 1);
            addEdge(bolg[i][j], to, 1);
        }
    }
//    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, 0, sizeof fa);
    memset(deep, 0, sizeof deep);
    memset(ansc, 0, sizeof ansc);
    memset(dis, 0, sizeof dis);
    for (int i = 1; i <= to; ++i) {
        if (vis[i]) continue;
        bfs(i);
        fa[i] = i;
        deep[i] = 0;
        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] == 0);
        }
        if (res == y) {
            assert(treeCut[y] == 0);
        }
        int ans = dis[x] + dis[y] - 2 * dis[res];
        assert(ans + treeCut[res] >= 0);
        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 0;
}

时间: 2024-10-24 13:32:03

hdu 3686 Traffic Real Time Query System 点双两通分量 + LCA的相关文章

UVALive 4839 HDU 3686 Traffic Real Time Query System

题意: 寻找图中从一条边到另一条边的路径上必须经过的点的个数 思路: 首先必经过的一定是割点  因此可以先做点双连通然后缩点  缩完点后形成了树  而且树上的路径是满足"非割点-割点-非割点-割点--"这样的模式的  路径u->v只需要求出他们的lca  则答案可以通过(dis[u]+dis[v]-dis[lca]*2)/2算出 注意: 这题缩点是通过边来进行的  因为这样可以使每条边都在一个连通块中 -- by wuyiqi PS: 代码中缩点的部分借鉴了 Sd.无心插柳 的代

【HDOJ】3686 Traffic Real Time Query System

这题做了几个小时,基本思路肯定是求两点路径中的割点数目,思路是tarjan缩点,然后以割点和连通块作为新节点见图.转化为lca求解.结合点——双连通分量与LCA. 1 /* 3686 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #inclu

Traffic Real Time Query System HDU - 3686

https://vjudge.net/problem/HDU-3686 先对原图求点双连通分量,求出每条边属于的点双 然后为原图中每一个点双新建一个点,向这个点双内每一个点连边,去掉原图所有边,得到一个新图(实际上是一棵树) 询问两条边a,b时,先找出它们属于的点双对应的点编号x,y,那么答案就是新树上x与y的最短路径中"非点双对应的点"的数量(由于实际是要求这两个点双在原图中的路径间割点数量,而只有割点才可能成为新树中要统计的点) https://blog.csdn.net/u013

UVALive-4839 HDU-3686 Traffic Real Time Query System 题解

题目大意: 有一张无向连通图,问从一条边走到另一条边必定要经过的点有几个. 思路: 先用tarjan将双连通分量都并起来,剩下的再将割点独立出来,建成一棵树,之后记录每个点到根有几个割点,再用RMQ求LCA计算. 注意:数组范围. 代码: 1 #include<cstdio> 2 #include<vector> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 const

Logstash+Elasticsearch+Kibana+Nginx set up our private log query system

Logstash+Elasticsearch+Kibana+S3+Nginx build our private log query system System structure How to setup Logstash-index (Logstash server) yum -y install java-1.7.0-openjdk Install and configure Elasticsearch ( Logstash 1.4.2 recommends Elasticsearch 1

HDU 4738 --Caocao&#39;s Bridges 【无向图边双联通 &amp;&amp; 求权值最小的桥 &amp;&amp; 模板】

Caocao's Bridges Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2641    Accepted Submission(s): 855 Problem Description Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. B

HDU 4738 Caocao&#39;s Bridges(双联通分量+并查集)

大意:有n座岛和m条桥,每条桥上有w个兵守着,现在要派不少于守桥的士兵数的人去炸桥,只能炸一条桥,使得这n座岛不连通,求最少要派多少人去. 思路:我们就是要缩点后直接求桥上人的最少数量.(PS:1.注意图如果不联通直接输出0.2.如果图中的桥上人为0,个那么要让一个人去.3.重边的问题.这里可以忽略) #include<map> #include<queue> #include<cmath> #include<cstdio> #include<stac

HDU 5869 Different GCD Subarray Query (GCD种类预处理+树状数组维护)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5869 问你l~r之间的连续序列的gcd种类. 首先固定右端点,预处理gcd不同尽量靠右的位置(此时gcd种类不超过loga[i]种). 预处理gcd如下代码,感觉真的有点巧妙... 1 for(int i = 1; i <= n; ++i) { 2 int x = a[i], y = i; 3 for(int j = 0; j < ans[i - 1].size(); ++j) { 4 int g

HDU 5869 Different GCD Subarray Query 树状数组 + 一些数学背景

http://acm.hdu.edu.cn/showproblem.php?pid=5869 题意:给定一个数组,然后给出若干个询问,询问[L, R]中,有多少个子数组的gcd是不同的. 就是[L, R]中不同区间的gcd值,有多少个是不同的. 给个样例 3 37 7 71 21 33 3 数学背景: 一个数字和若N个数字不断GCD,其结果只有loga[i]种,为什么呢?因为可以把a[i]质因数分解,其数目最多是loga[i]个数字相乘.(最小的数字是2,那么loga[i]个2相乘也爆了a[i]