sgu529. It's Time to Repair the Roads 简化版动态最小生成树

1 篇文章 0 订阅

题目大意:

给出n个点m条边,然后给出q个询问,表示把目前第numi条边的边权修改为di后的mst。


一个分治算法

两个重要的操作  Contraction 和 Reduction 操作。 详见论文《Offline Algorithms for Dynamic Minimum Spanning Tree Problems》


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>

#define MAXT 50010
#define MAXM 100010
#define MAXN 50010

using namespace std;
const long long INF = 1LL <<40;
int n,m,q;
int x[MAXM],y[MAXM],num[MAXM],d[MAXM],f[MAXN],ord[MAXM],t[MAXN];
long long z[MAXM],c[MAXM], answer;

struct Edge{
             int cnt;
             int a[MAXM*5],b[MAXN*5];
             inline void renew(int);
             inline void merge(int u,int v);
             inline int find(int v);
}edge[20];
inline void Edge::renew(int top = 0)
{
       for (;cnt != top; --cnt)
           f[a[cnt]] = b[cnt];
}
inline void Edge::merge(int v,int u)
{
       int _v = find(v);
       int _u = find(u);
       a[++cnt] = _v;
       b[cnt] = f[_v];
       f[_v] = _u;
}
inline int Edge::find(int v)
{
       if (!f[v]) return v;
       int ret = v;
       while (f[ret]) ret = f[ret];
       while (f[v] != ret)
       {
             a[++cnt] = v;
             b[cnt] = f[v];
             f[v] = ret; v = b[cnt];
       }
       return ret;
}
void  Qsort(int l,int r)
{
      long long k = z[ord[(l+r)/2]];
      int i = l, j = r;
      while (i<j)
      {
            while (z[ord[i]] < k) i++;
            while (z[ord[j]] > k) j--;
            if (i<=j)
               swap(ord[i++], ord[j--]);
      }
      if (i<r) Qsort(i,r);
      if (l<j) Qsort(l,j);
}
inline void  work(int l ,int r,int dep)
{
      Edge &e = edge[dep];
      e.cnt = 0;
      if (l>r) return ;
      if (l == r)
      {
            z[num[l]] = c[num[l]] = d[l];
            Qsort(1,m);  
            long long ans =  answer;
            for (int i = 1; i <= m;++i)
            if (e.find(x[ord[i]]) != e.find(y[ord[i]]))
            {
                 ans+=z[ord[i]];
                 e.merge(x[ord[i]],y[ord[i]]);
            }
            e.renew();
            printf("%lld\n",ans);
            return ;
      }
      int temp_m = m;
      long long  temp_ans = answer;
      //Contrresume;
      for (int i = l; i <= r; ++i) z[num[i]] = -INF;  
      Qsort(1,m);
      t[0] = 0;
      for (int i = 1; i <= m; ++i)
      {
          if (e.find(x[ord[i]]) != e.find(y[ord[i]]))
          {
              if (z[ord[i]] != -INF) t[++t[0]] = ord[i];
              e.merge(x[ord[i]],y[ord[i]]);
          }
      }
      e.renew();
      for (int i = 1; i <= t[0] ; ++i)
      {
          e.merge(x[t[i]], y[t[i]]);
          answer +=z[t[i]];
      }
      int temp_cnt = e.cnt;   
      //Reduction
      for (int i = l; i <= r; ++i) z[num[i]] = INF;
      Qsort(1,m);
      t[0] =0;
      for (int i = 1; i <= m; ++i)
      {
         if (e.find(x[ord[i]]) != e.find(y[ord[i]])) 
         e.merge(x[ord[i]], y[ord[i]]);
         else
         {
             if (z[ord[i]] != INF) t[++t[0]] = i;
         }
      }
      for (int i = t[0]; i ; --i) swap(ord[t[i]],ord[m--]);
      e.renew(temp_cnt);
      for (int i =l ; i<=r; ++i)  z[num[i]] = c[num[i]];
      work(l,(l+r)/2,  dep+1);
      work((l+r)/2+1,r,dep+1);
      e.renew();
      answer = temp_ans;
      m = temp_m;
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m ;++i)
    {
        scanf("%d %d %d", &x[i],&y[i],&z[i]);
        c[i] = z[i];
        ord[i] = i;
    }   
    scanf("%d",&q);
    Qsort(1,m);
    for (int i = 1; i <= q; ++i)
        scanf("%d %d", &num[i], &d[i]);
    work(1,q,0);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值