hdu6200mustedge mustedge mustedge

Give an connected undirected graph with n nodes and m edges, (n,m≤105) which has no selfloops or multiple edges initially.
Now we have q operations (q≤105):

⋅1 u v: add an undirected edge from u to v; (u≠v&&1≤u,v≤n)
⋅2 u v: count the number of mustedges from u to v; (1≤u,v≤n).

mustedge: we define set Ei as a path from u to v which contain edges in this path, and |∩k1Ei| is the number of mustedges. |x| means size of set x, and E1,E2…Ek means all the paths.
It’s guaranteed that ∑n,∑m,∑q≤106

Please note that maybe there are more than one edges between two nodes after we add edges. They are not the same, which means they can be in a set at the same time. Read the sample data for more information.

Input
Input starts with an integer T, denoting the number of test cases.
For each case:
First line are two number n and m;
Then next m lines, each contains two integers u and v, which indicates an undirected edge from u to v;
Next line contains a number q, the number of operations;
Then next q lines, contains three integers x, u and v where x
is the operation type, which describes an operation.

Output
For each test case, output “Case #x:” where x is the test case number starting from 1.
In each test case, print a single number one line when query the number of mustedges
.
Sample Input

2
4 3
1 2
2 3
3 4
5
2 1 4
1 2 3
2 1 4
2 2 3
2 2 4
8 9
1 2
2 3
1 3
3 4
4 5
4 6
5 7
5 8
7 8
5
2 7 8
2 1 6
2 4 7
1 6 8
2 5 6

Sample Output

Case #1:
3
2
0
1
Case #2:
0
2
1
0

题意:有两种查询 第一种是将u,v两个点之间连一条边,另一种是查询u到v路径上的割边有几条。
题解:具体方法和我上篇博客差不多是从航线规划中抽出的模型。这个问题最直接的想法就是缩点然后生成一棵树,然后树剖维护路径。那么复杂度是qlognlogn,每次查询树剖一个log,线段树一个大常数log。这题首先卡你内存。。。我的AC代码C++可以,G++不行。然后卡你时间。。。应该是卡了树剖那个log。所以只能用另一个暴力合并的维护子树深度的方法。
=-=。做这题的时候深深感受到了没有大神给我看思路自己想自己码的绝望。。平时都觉得没事。。。码不出还能看题解。。这次有点绝望。。。在icpccamp看到了一波大佬的提示,然后就自己码了好久=-=回来回馈一下社会
听说还能用lct做 蒟蒻好久以前就准备学到现在还没看懂定义ORZ

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

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

const int N = 1e5 + 1;

vector<pair<int,int> > edges;
vector<int> G[N],g[N];
bool is_cut[N*2];
int dfn[N],low[N],L[N],R[N];
int Index = 0,id = 0;
int fa[N],f[N][21],dep[N];
int n;
void init()
{
    Index = 0, id = 0;
    memset(dfn,0,sizeof(dfn));
    memset(is_cut,0,sizeof(is_cut));
    for(int i = 0;i<N;i++)
        G[i].clear(),g[i].clear(),fa[i] = i;
    edges.clear();
}
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)
            continue;
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u] = min(low[v],low[u]);
            if(low[v] > dfn[u])
                is_cut[G[u][i]] = is_cut[G[u][i] ^ 1] = true;
        }   
        else low[u] = min(low[u],dfn[v]);
    }
}
int find(int x)
{
    if(x != fa[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_Graph()
{
    for(int i = 1;i<=n;i++)
        tarjan(i,i);    
    for(int i = 0;i<edges.size();i++)
    {
        int u = edges[i].first, v = edges[i].second;
        if(!is_cut[i])
            merge(u,v);
    }
    for(int i = 0;i<edges.size();i++)
    {
        int u = edges[i].first, v = edges[i].second;
        if(is_cut[i])
            g[find(u)].push_back(find(v));
    }
    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());
    }
}
void dfs(int u,int Fa,int d)
{
    dep[u] = d,f[u][0] = Fa;
    for(int i = 1;i<=20;i++)
        f[u][i] = f[f[u][i-1]][i-1];
    L[u] = ++ id;
    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 vis,sum;
}t[N*4];
void push_down(int l,int r,int step)
{
    int mid = (l + r) / 2;
    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].vis * (mid - l + 1);
    t[step * 2 + 1].sum += t[step].vis * (r - (mid + 1) + 1);
    t[step].vis = 0;
}
void build()
{
    memset(t,0,sizeof(t));
}
void update(int l,int r,int ql,int qr,int val,int step)
{
    if(l == ql && r == qr)
    {
        t[step].vis += val;
        t[step].sum += (r - l + 1) * val;
        return;
    }
    int mid = (l + r) / 2;
    push_down(l,r,step);
    if(qr <= mid)
        update(l,mid,ql,qr,val,step*2);
    else if(ql > mid)
        update(mid + 1,r, ql,qr,val,step*2+1);
    else update(l,mid,ql,mid,val,step * 2),update(mid+1,r,mid+1,qr,val,step*2+1);
}
int query(int x,int l,int r,int step)
{
    if(l == r)
        return t[step].sum;
    int mid = (l + r) / 2;
    push_down(l,r,step);
    if(x <= mid)
        return query(x,l,mid,step*2);
    else return query(x,mid+1,r,step*2+1);
}
void link(int u,int v)
{
    u = find(u), v = find(v);
    int anc = find(lca(u,v));
    while(find(u) != find(anc))
    {
        update(1,n,L[find(u)],R[find(u)],-1,1);
        merge(find(u),f[find(u)][0]);
    }
    while(find(v) != find(anc))
    {
        update(1,n,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,n,1) + query(L[v],1,n,1) - 2 * query(L[anc],1,n,1);
}
int main()
{
    int T;
    scanf("%d", &T);
    int ka = 0;
    while(T--)
    {
        int m;
        init();
        scanf("%d%d",&n,&m);    
        for(int i = 0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v);
        }
        Create_Graph();
        build();
        dfs(find(1),find(1),0);
        for(int i = 1;i<=n;i++)
            if(find(i) == i)
                update(1,n,L[i],L[i],dep[i],1);
        int q;
        scanf("%d",&q);
        printf("Case #%d:\n",++ka);
        for(int i = 0;i<q;i++)
        {
            int op,x,y;
            scanf("%d%d%d",&op,&x,&y);
            if(op == 1)
                link(x,y);
            else printf("%d\n",Get_Ans(x,y));
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值