• Bridges: The Final Battle


    对修改操作按时间分治,设$solve(l,r,n,m)$为考虑时间在$[l,r]$的修改操作,作用范围是$n$个点,$m$条边的图。

    若$l=r$,则暴力Tarjan统计桥边个数即可。

    否则提取出$[l,r]$内涉及修改的所有边$E$,并将端点标记为$V$,显然$|V|=O(|E|)$。

    加入$m$条边里除了$E$之外的所有边,显然无论怎么修改,这些边都会存在。

    Tarjan求出边双连通分量,将边双缩点,可以得到一个森林,那么非树边永远都不可能成为桥,直接删除即可。

    还可以注意到的是,还未加入的边的端点只可能在$V$中,因此可以求出$V$的虚树,不在虚树上的边永远都是桥,加入答案并删除即可。

    而在虚树上的边,每条压缩边都表示一条链,需要额外记录这条树边表示几条桥边$w$,当以后这条树边成为桥边时,答案应该直接加上$w$。

    经过以上几步处理之后,$n$和$m$均缩为$O(|V|)=O(|E|)=O(r-l)$。

    取$mid=lfloorfrac{l+r}{2} floor$,递归$solve(l,mid,n',m')$,然后暴力处理所有$[l,mid]$的修改,再递归$solve(mid+1,r,n',m')$即可。

    时间复杂度$T(n)=2T(frac{n}{2})+O(n)=O(nlog n)$。

    #include<cstdio>
    #include<algorithm>
    #include<map>
    using namespace std;
    typedef pair<int,int>P;
    const int N=100010,M=100010,K=19;
    int n,m,i,ans[M];
    bool use[M],ex[M],cut[M],vis[N];
    int g[N],v[M<<1],w[M<<1],nxt[M<<1],ed,f[N],dfn[N],low[N],num,from[N];
    int G[N],V[N<<1],W[N<<1],NXT[N<<1],ED,id[N],sum[N],vip[N];
    int O,ce,all,pos[M],q[K][M];
    map<P,int>T;
    struct E{
      int x,y,w;
      E(){}
      E(int _x,int _y,int _w){x=_x,y=_y,w=_w;}
    }e[K][M];
    inline int ask(int x,int y){
      if(x==y)return 0;
      if(x>y)swap(x,y);
      int&t=T[P(x,y)];
      if(!t)e[0][t=++ce]=E(x,y,0);
      return t;
    }
    inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;}
    inline void ADD(int x,int y,int z){V[++ED]=y;W[ED]=z;NXT[ED]=G[x];G[x]=ED;}
    void tarjan(int x){
      dfn[x]=low[x]=++num;
      for(int i=g[x];i;i=nxt[i])if(!dfn[v[i]]){
        f[v[i]]=w[i],tarjan(v[i]);
        if(low[x]>low[v[i]])low[x]=low[v[i]];
      }else if(f[x]!=w[i]&&low[x]>dfn[v[i]])low[x]=dfn[v[i]];
      if(f[x]&&low[x]==dfn[x])cut[f[x]]=1;
    }
    void dfs(int x,int y){
      from[x]=y;
      for(int i=g[x];i;i=nxt[i])if(!from[v[i]]&&!cut[w[i]])dfs(v[i],y);
    }
    inline void newedge(int x,int y,int w){all-=w;e[O][++ce]=E(x,y,w);}
    void compress(int x,int y){
      int d=0;
      vis[x]=1;
      for(int i=G[x];i;i=NXT[i]){
        int u=V[i];
        if(u==y)continue;
        sum[u]=sum[x]+W[i];
        compress(u,x);
        if(!id[u])continue;
        d++;
        id[x]^=id[u];
      }
      if(d>1)vip[x]=1;
      if(vip[x]){
        for(int i=G[x];i;i=NXT[i]){
          int u=V[i];
          if(u==y)continue;
          int t=id[u];
          if(t)newedge(x,t,sum[t]-sum[x]);
        }
        id[x]=x;
      }
    }
    void solve(int o,int l,int r,int n,int m,int pre){
      O=o+1;
      int i;
      if(l==r){
        for(i=1;i<=m;i++)cut[i]=0;
        for(ed=0,i=1;i<=n;i++)g[i]=f[i]=dfn[i]=low[i]=from[i]=0;
        num=0;
        e[o][q[o][l]].w^=1;
        for(i=1;i<=m;i++)if(e[o][i].w){
          int x=e[o][i].x,y=e[o][i].y;
          add(x,y,i),add(y,x,i);
        }
        for(i=1;i<=n;i++)if(!dfn[i])tarjan(i);
        for(i=1;i<=m;i++)if(cut[i])pre+=e[o][i].w;
        e[o][q[o][l]].w^=1;
        ans[l]=pre;
        return;
      }
      for(i=1;i<=m;i++)use[i]=cut[i]=pos[i]=0;
      for(ed=0,i=1;i<=n;i++)g[i]=f[i]=dfn[i]=low[i]=from[i]=0;
      num=0;
      int cnt=0;
      for(i=l;i<=r;i++)use[q[o][i]]=1;
      for(i=1;i<=m;i++)if(!use[i]&&e[o][i].w){
        int x=e[o][i].x,y=e[o][i].y;
        add(x,y,i),add(y,x,i);
      }
      for(i=1;i<=n;i++)if(!dfn[i])tarjan(i);
      for(i=1;i<=n;i++)if(!from[i])dfs(i,++cnt);
      for(ED=0,i=1;i<=cnt;i++)vis[i]=vip[i]=G[i]=id[i]=sum[i]=0;
      ce=all=0;
      for(i=1;i<=m;i++)if(!use[i]&&e[o][i].w){
        int x=e[o][i].x,y=e[o][i].y;
        x=from[x],y=from[y];
        if(x==y)continue;
        ADD(x,y,e[o][i].w),ADD(y,x,e[o][i].w);
        all+=e[o][i].w;
      }
      for(i=l;i<=r;i++){
        int t=q[o][i];
        if(!t)continue;
        vip[from[e[o][t].x]]=vip[from[e[o][t].y]]=1;
      }
      for(i=1;i<=cnt;i++)if(vip[i]&&!vis[i])compress(i,0);
      int mid=(l+r)>>1,_ce=ce,cv=0;
      for(i=1;i<=cnt;i++)if(vip[i])vip[i]=++cv;
      pre+=all;
      for(i=1;i<=ce;i++)e[o+1][i].x=vip[e[o+1][i].x],e[o+1][i].y=vip[e[o+1][i].y];
      for(i=1;i<=m;i++)if(use[i]){
        int x=e[o][i].x,y=e[o][i].y;
        e[o+1][++ce]=E(vip[from[x]],vip[from[y]],e[o][i].w);
        pos[i]=ce;
      }
      for(i=l;i<=r;i++)q[o+1][i]=pos[q[o][i]];
      solve(o+1,l,mid,cv,ce,pre);
      ce=_ce;
      for(i=1;i<=m;i++)use[i]=0;
      for(i=l;i<=r;i++)use[q[o][i]]=1;
      for(i=1;i<=m;i++)if(use[i])ex[i]=e[o][i].w;
      for(i=l;i<=mid;i++)ex[q[o][i]]^=1;
      for(i=1;i<=m;i++)if(use[i])e[o+1][++ce].w=ex[i];
      solve(o+1,mid+1,r,cv,ce,pre);
    }
    int main(){
      freopen("bridges3.in","r",stdin);freopen("bridges3.out","w",stdout);
      scanf("%d%d",&n,&m);
      for(i=1;i<=m;i++){
        char s[9];
        int x,y;
        scanf("%s%d%d",s,&x,&y);
        q[0][i]=ask(x,y);
      }
      solve(0,1,m,n,ce,0);
      for(i=1;i<=m;i++)printf("%d
    ",ans[i]);
    }
    

      

  • 相关阅读:
    黑马程序员——正则表达式
    黑马程序员——集合框架知识点总结
    黑马程序员——String类知识点详细
    黑马程序员——System、Runtime、Date、Calender、Math静态类
    黑马程序员——IO流总结
    黑马程序员——多线程中的安全问题 :
    获取一段字符串中含有某一子字符串的个数的方法定义:
    debian彻底删除apache2
    linux下mysql的安装
    markdown学习
  • 原文地址:https://www.cnblogs.com/clrs97/p/7785219.html
Copyright © 2020-2023  润新知