bzoj1969LANE 航线规划

对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系。 星际空间站的Samuel II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些星球从1开始编号1、2、3……。 一些先遣飞船已经出发,在星球之间开辟探险航线。 探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星球也可以使用这条航线。 例如下图所示: 在5个星球之间,有5条探险航线。 A、B两星球之间,如果某条航线不存在,就无法从A星球抵达B星球,我们则称这条航线为关键航线。 显然上图中,1号与5号星球之间的关键航线有1条:即为4-5航线。 然而,在宇宙中一些未知的磁暴和行星的冲撞,使得已有的某些航线被破坏,随着越来越多的航线被破坏,探险飞船又不能及时回复这些航线,可见两个星球之间的关键航线会越来越多。 假设在上图中,航线4-2(从4号星球到2号星球)被破坏。此时,1号与5号星球之间的关键航线就有3条:1-3,3-4,4-5。 小联的任务是,不断关注航线被破坏的情况,并随时给出两个星球之间的关键航线数目。现在请你帮助完成。
Input
第一行有两个整数N,M。表示有N个星球(1< N < 30000),初始时已经有M条航线(1 < M < 100000)。随后有M行,每行有两个不相同的整数A、B表示在星球A与B之间存在一条航线。接下来每行有三个整数C、A、B。C为1表示询问当前星球A和星球B之间有多少条关键航线;C为0表示在星球A和星球B之间的航线被破坏,当后面再遇到C为1的情况时,表示询问航线被破坏后,关键路径的情况,且航线破坏后不可恢复; C为-1表示输入文件结束,这时该行没有A,B的值。被破坏的航线数目与询问的次数总和不超过40000。
Output
对每个C为1的询问,输出一行一个整数表示关键航线数目。 注意:我们保证无论航线如何被破坏,任意时刻任意两个星球都能够相互到达。在整个数据中,任意两个星球之间最多只可能存在一条直接的航线。
Sample Input
5 5
1 2
1 3
3 4
4 5
4 2
1 1 5
0 4 2
1 5 1
-1

Sample Output
1
3

题意:给你一张无向图,两种操作一种是把路径u,v破坏掉第二种问你路径u,v上有多少条割边
思路:首先缩点很容易想到,缩点后成为一棵树,很容易知道缩点所包含的所有边不可能为割边,因为缩点是将成环的点缩成一个点。然后还可以知道缩点后树上每条边都是割边,即我们要求的查询数量。这样我们的查询就转变成了,在缩点后u所属的集合到v所属集合的路径上有多少条边。树上操作很容易想到dis(u) + dis(v) - 2*dis(lca(u,v))那么现在比较尴尬的就是破坏u,v这种想法了。想法1:破坏u,v之间的路径会把u,v之间的边全部破坏,如果破坏的边是环上的边那么对答案无影响。如果破坏的是割边那么割边数量-1。等效操作就是连接一条u到v的边,使其成环。那么我们就需要从被破坏的树的最终形态开始加边加到刚缩点的状态。然后每次加边会让u的子树向上提升,v的子树也向上提升,我们只要暴力合并就可以了。想法2:我们定义未被破坏的边为白边,破坏了为黑边,那么每次破坏就是把一条路径描黑,自然想到树链剖分。

这里由于沈阳网络赛的MUSTEDGE卡了树链剖分。。。这里 用了暴力合并维护子树的方法2333

这题。。。如果用树链剖分的话大概就是很多个板子一起打吧2333
虽然有debug代码=-=但是我写的感觉比别人长好多

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
using namespace std;


//thanks to pyf ...
//thanks to qhl ...

const int N = 3e5 + 7;

vector<int>G[N];
vector<pair<int, int> > edges;
vector<int> g[N];
bool is_cut[N];
map<pair<int, int>, bool > is_del;
int dfn[N], low[N], fa[N], L[N], R[N];
int f[N][21], dep[N];
int Index = 0, id = 0;
void init()
{
    is_del.clear();
    for (int i = 0; i < N; i++)
        G[i].clear(), g[i].clear(), fa[i] = i;
    edges.clear();
    memset(dfn, 0, sizeof(dfn));
    memset(is_cut, 0, sizeof(is_cut));
    memset(low, 0, sizeof(low));
    Index = id = 0;
}
void add_edge(int u, int v)
{
    edges.push_back(make_pair(u, v));
    G[u].push_back(edges.size() - 1);
    edges.push_back(make_pair(v, u));
    G[v].push_back(edges.size() - 1);
}
void tarjan(int u, int Fa)
{
    dfn[u] = low[u] = ++ Index;
    for (int i = 0; i < G[u].size(); i++)
    {
        int v = edges[G[u][i]].second;
        if (v == Fa || is_del.count(make_pair(u, v)))
            continue;
        if (!dfn[v])
        {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u])
                is_cut[G[u][i] ^ 1] = is_cut[G[u][i]] = 1;
        }
        else low[u] = min(low[u], dfn[v]);
    }
}
int find(int x)
{
    if (fa[x] != x)
        fa[x] = find(fa[x]);
    return fa[x];
}
void merge(int u, int v)
{
    u = find(u), v = find(v);
    if (u == v)
        return;
    if (dep[u] > dep[v])
        swap(u, v);
    fa[v] = u;
}
void Create_Tree(int n)
{
    for (int i = 1; i <= n; i++)
    {
        sort(G[i].begin(), G[i].end());
        G[i].erase(unique(G[i].begin(), G[i].end()), G[i].end());
    }
    for (int i = 1; i <= n; i++)
        if (!dfn[i])
            tarjan(i, i);
    for (int i = 0; i != edges.size(); i ++)
        if (!is_cut[i] && !is_del.count(make_pair(edges[i].first, edges[i].second)))
            merge(edges[i].first, edges[i].second);
    for (int i = 0; i != edges.size(); i++)
        if (is_cut[i] && !is_del.count(make_pair(edges[i].first, edges[i].second)))
            g[find(edges[i].first)].push_back(find(edges[i].second));
    for (int i = 1; i <= n; i++)
    {
        sort(g[i].begin(), g[i].end());
        vector<int> :: iterator it = unique(g[i].begin(), g[i].end());
        g[i].erase(it, g[i].end());
    }
    // for (int i = 1; i <= n; i++)
    // {
    //  cout << "*" << i;
    //  for (int j = 0; j < g[i].size(); j++)
    //      cout << "---->" << g[i][j];
    //  cout << endl;
    // }
}
void dfs(int u, int fa, int d)
{
    L[u] = ++ id;
    dep[u] = d, f[u][0] = fa;
    for (int i = 1; i <= 20; i++)
        f[u][i] = f[f[u][i - 1]][i - 1];
    for (int i = 0; i != g[u].size(); i ++)
    {
        int v = g[u][i];
        if (v == fa)
            continue;
        dfs(v, u, d + 1);
    }
    R[u] = id;
}
int lca(int u, int v)
{
    if (dep[u] < dep[v])
        swap(u, v);
    for (int i = 20; i >= 0; i--)
        if (dep[f[u][i]] >= dep[v])
            u = f[u][i];
    if (u == v)
        return u;
    for (int i = 20; i >= 0; i--)
        if (f[u][i] != f[v][i])
            u = f[u][i], v = f[v][i];
    return f[u][0];
}
struct Tree
{
    int l, r;
    int sum, vis;
} t[N * 4];
void push_down(int step)
{
    if (!t[step].vis)
        return;
    t[step * 2].vis += t[step].vis;
    t[step * 2 + 1].vis += t[step].vis;
    t[step * 2].sum += (t[step * 2].r - t[step * 2].l + 1) * t[step].vis;
    t[step * 2 + 1].sum += (t[step * 2 + 1].r - t[step * 2 + 1].l + 1) * t[step].vis;
    t[step].vis = 0;
}
void build(int l, int r, int step)
{
    t[step].l = l, t[step].r = r, t[step].vis = 0, t[step].sum = 0;
    if (l == r)
        return;
    int mid = (l + r) / 2;
    build(l, mid, step * 2);
    build(mid + 1, r, step * 2 + 1);
}
void update(int l, int r, int val, int step)
{
    if (t[step].l == l && r == t[step].r)
    {
        t[step].vis += val;
        t[step].sum += val * (t[step].r - t[step].l + 1);
        return;
    }
    int mid = (t[step].l + t[step].r) / 2;
    push_down(step);
    if (r <= mid)
        update(l, r, val, step * 2);
    else if (l > mid)
        update(l, r, val, step * 2 + 1);
    else update(l, mid, val, step * 2), update(mid + 1, r, val, step * 2 + 1);
}
int query(int x, int step)
{
    if (t[step].l == t[step].r)
        return t[step].sum;
    int mid = (t[step].l + t[step].r) / 2;
    push_down(step);
    if (x <= mid)
        return query(x, step * 2);
    else if (x > mid)
        return query(x, step * 2 + 1);
}
void del(int u, int v)
{
    u = find(u), v = find(v);
    int anc = find(lca(u, v));
    while (find(u) != find(anc))
    {
        update(L[find(u)], R[find(u)], -1, 1);
        merge(find(u), f[find(u)][0]);
    }
    while (find(v) != find(anc))
    {
        update(L[find(v)], R[find(v)], -1, 1);
        merge(find(v), f[find(v)][0]);
    }
}
int Get_Ans(int u, int v)
{
    u = find(u), v = find(v);
    int anc = find(lca(u, v));
    return query(L[u], 1) + query(L[v], 1) - 2 * query(L[anc], 1);
}
vector<pair<bool, pair<int, int> > > Q;
vector<int> ac;
int main()
{
    int n, m;
    while (scanf("%d%d", &n, &m) == 2)
    {
        init();
        ac.clear();
        for (int i = 0; i < m; i++)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            add_edge(u, v);
        }
        Q.clear();
        int op, x, y;
        while (~scanf("%d", &op))
        {
            if (op == -1)
                break;
            scanf("%d%d", &x, &y);
            Q.push_back(make_pair(op, make_pair(x, y)));
            if (!op)
            {
                is_del[make_pair(x, y)] = 1;
                is_del[make_pair(y, x)] = 1;
            }
        }
        Create_Tree(n);
        dfs(find(1), find(1), 0);
        build(1, n, 1);
        for (int i = 1; i <= n; i++)
            if (find(i) == i)
                update(L[i], L[i], dep[i], 1);
        for (int i = Q.size() - 1; i >= 0; i --)
        {
            op = Q[i].first;
            x = find(Q[i].second.first);
            y = find(Q[i].second.second);
            if (!op)
                del(x, y);
            else
                ac.push_back(Get_Ans(x, y));
        }
        reverse(ac.begin(), ac.end());
        for (int i = 0; i != ac.size(); i++)
            printf("%d\n", ac[i]);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值