2238: Mst

2238: Mst

Time Limit: 20 Sec   Memory Limit: 256 MB
Submit: 319   Solved: 98
[ Submit][ Status][ Discuss]

Description

给出一个 N 个点 M 条边的无向带权图,以及 Q 个询问,每次询问在图中删掉一条边后图的最小生成树。 ( 各询问间独立,每次询问不对之后的询问产生影响,即被删掉的边在下一条询问中依然存在 )
 

Input

第一行两个正整数N,M(N<=50000,M<=100000)表示原图的顶点数和边数。
下面M行,每行三个整数X,Y,W描述了图的一条边(X,Y),其边权为W(W<=10000)。保证两点之间至多只有一条边。
接着一行一个正整数Q,表示询问数。(1<=Q<=100000)
下面Q行,每行一个询问,询问中包含一个正整数T,表示把编号为T的边删掉(边从1到M按输入顺序编号)。
 

Output

Q 行,对于每个询问输出对应最小生成树的边权和的值,如果图不连通则输出 “Not connected”

Sample Input

4 4
1 2 3
1 3 5
2 3 9
2 4 1
4
1
2
3
4

Sample Output

15
13
9
Not connected

样例解释:


数据规模:
10%的数据N,M,Q<=100。
另外30%的数据,N<=1000
100%的数据如题目。

HINT

 更新数据---2015.6.9

Source

[ Submit][ Status][ Discuss]

先求一个最小生成树,建出这棵树,对剩下的边分类讨论

如果一条边不在这棵树上,那么删去它,答案肯定不变
考虑一个询问,删去一条边等价于构成了两个连通块
要想继续保持树形态,只需要选出一条能连接这两个块的边即可

而对于这条边,一定是非树边,加入这棵树上,就会形成一个环
对于这个环,删去任意一条边,都可以用这条边替换
于是对于每条非树边,找到树上唯一的那条路径,拆成两条链,都可以用这条边更新答案
用LCT可以实现这些操作(不想写树剖。。。)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
 
const int maxn = 5E4 + 50;
const int maxm = maxn * 2;
const int T = 16;
const int INF = ~0U>>1;
 
struct E{
    int x,y,w; E(){}
    E(int x,int y,int w): x(x),y(y),w(w){}
    bool operator < (const E &B) const {return w < B.w;}
}edgs[maxm];
 
int n,m,tot,q,tp,cnt,L[maxn],mfa[maxn][T],Ans[maxn],son[maxm],bfa[maxn]
    ,A[maxm],ch[maxn][2],stk[maxn],fa[maxn],pfa[maxn],Mark[maxn],rev[maxn];
bool bo[maxm];
 
vector <pair<int,int> > v[maxn];
 
void pushdown(int x)
{
    if (rev[x])
    {
        swap(ch[x][0],ch[x][1]);
        for (int i = 0; i < 2; i++)
            if (ch[x][i]) rev[ch[x][i]] ^= 1;
        rev[x] ^= 1;
    }
    if (Mark[x] != INF)
    {
        Ans[x] = min(Ans[x],Mark[x]);
        for (int i = 0; i < 2; i++)
            if (ch[x][i]) Mark[ch[x][i]] = min(Mark[ch[x][i]],Mark[x]);
        Mark[x] = INF;
    }
}
 
void rotate(int x)
{
    int y = fa[x],z = fa[y];
    pfa[x] = pfa[y]; pfa[y] = 0;
    int d = ch[y][0] == x ? 0 : 1;
    ch[y][d] = ch[x][d^1]; ch[x][d^1] = y;
    fa[ch[y][d]] = y; fa[y] = x; fa[x] = z;
    if (z) ch[z][ch[z][1] == y] = x;
}
 
void splay(int x)
{
    for (int z = x; z; z = fa[z]) stk[++tp] = z;
    while (tp) pushdown(stk[tp--]);
    for (int y = fa[x]; y; rotate(x),y = fa[x])
        if (fa[y]) rotate((ch[y][0] == x) ^ (ch[fa[y]][0] == y) ? x : y);
}
 
void Access(int x)
{
    for (int u = 0; x; u = x,x = pfa[x])
    {
        splay(x); if (ch[x][1]) pfa[ch[x][1]] = x,fa[ch[x][1]] = 0;
        ch[x][1] = u; if (u) pfa[u] = 0,fa[u] = x;
    }
}
 
int getfa(int k) {return k == bfa[k] ? k : bfa[k] = getfa(bfa[k]);}
bool cmp(const int &x,const int &y) {return edgs[x].w < edgs[y].w;}
void ChangeRoot(int x) {Access(x); splay(x); rev[x] ^= 1;}
void Add(int x,int y) {ChangeRoot(x); pfa[x] = y; Access(x); splay(x);}
 
void Dfs(int x,int from)
{
    Ans[x] = Mark[x] = INF;
    for (int i = 1; i < T; i++) mfa[x][i] = mfa[mfa[x][i-1]][i-1];
    for (int i = 0; i < v[x].size(); i++)
    {
        int to = v[x][i].first,id = v[x][i].second;
        if (to == from) continue;
        mfa[to][0] = x; L[to] = L[x] + 1;
        son[id] = to; Add(x,to); Dfs(to,x);
    }
}
 
int LCA(int p,int q)
{
    if (L[p] < L[q]) swap(p,q);
    for (int i = T - 1; i >= 0; i--)
        if (L[p] - (1 << i) >= L[q])
            p = mfa[p][i];
    if (p == q) return p;
    for (int i = T - 1; i >= 0; i--)
        if (mfa[p][i] != mfa[q][i])
            p = mfa[p][i],q = mfa[q][i];
    return mfa[p][0];
}
 
void pushall(int x)
{
    pushdown(x);
    for (int i = 0; i < 2; i++)
        if (ch[x][i]) pushall(ch[x][i]);
}
 
int getint()
{
    char ch = getchar(); int ret = 0;
    while (ch < '0' || '9' < ch) ch = getchar();
    while ('0' <= ch && ch <= '9')
        ret = ret * 10 + ch - '0',ch = getchar();
    return ret;
}
 
int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
    #endif
     
    n = getint(); m = getint();
    for (int i = 1; i <= m; i++)
    {
        int x = getint(),y,w;
        y = getint(); w = getint();
        edgs[i] = E(x,y,w); A[i] = i;
    }
    sort(A + 1,A + m + 1,cmp);
    for (int i = 1; i <= n; i++) bfa[i] = i;
    for (int i = 1; i <= m; i++)
    {
        E e = edgs[A[i]];
        int fx = getfa(e.x),fy = getfa(e.y);
        if (fx == fy) continue; ++cnt;
        bfa[fx] = fy; tot += e.w; bo[A[i]] = 1;
        v[e.x].push_back(make_pair(e.y,A[i]));
        v[e.y].push_back(make_pair(e.x,A[i]));
    }
    if (cnt < n - 1)
    {
        q = getint();
        while (q--) puts("Not connected");
        return 0;
    }
    L[1] = 1; Dfs(1,0);
    for (int i = 1; i <= m; i++)
    {
        if (bo[i]) continue;
        E e = edgs[i]; int lca = LCA(e.x,e.y);
        if (lca == e.x)
        {
            ChangeRoot(e.y); Access(e.x); splay(e.x);
            Mark[ch[e.x][0]] = min(Mark[ch[e.x][0]],e.w);
        }
        else if (lca == e.y)
        {
            ChangeRoot(e.x); Access(e.y); splay(e.y);
            Mark[ch[e.y][0]] = min(Mark[ch[e.y][0]],e.w);
        }
        else
        {
            ChangeRoot(e.x); Access(lca); splay(lca);
            Mark[ch[lca][0]] = min(Mark[ch[lca][0]],e.w);
            ChangeRoot(e.y); Access(lca); splay(lca);
            Mark[ch[lca][0]] = min(Mark[ch[lca][0]],e.w);
             
        }
    }
    for (int i = 1; i <= n; i++) if (!fa[i]) pushall(i);
     
    q = getint();
    while (q--)
    {
        int k = getint();
        if (!bo[k]) printf("%d\n",tot);
        else
        {
            int x = son[k];
            if (Ans[x] == INF) puts("Not connected");
            else printf("%d\n",tot - edgs[k].w + Ans[x]);
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值