• 圆方树


    题解:

    好像挺简单的

    首先普通的圆方树处理的是仙人掌上的问题

    构造圆方树的方法就是对于每个环 建立一个方点

    然后原先不在环上的边,就用圆点和圆点相连

    对于在环上的边,将点连向方点

    然后我们来证明一个这是一棵树

    1.首先这张图联通是比较显然的

    2.方点数=原先环数=e-v+1

    当前点数=方点+v=e+1=当前边数+1

    显然满足这两条的肯定是树了

    1.仙人掌最大独立集

    我们知道基环树的最大独立集就是对环上每个点的树都跑一遍

    再在环上跑一遍

    树上类似,我们利用dfs序,将不在环上的边按照普通的树形dp处理

    对于在环上的边,我们放在环的最高处处理

    方法就是从最低点到最高点dp一下(注意我们之前的时候是没有把这些环边计入父亲答案的)

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for(int i=h;i<=t;i++)
    #define dep(i,t,h) for(int i=t;i>=h;i--)
    #define ll long long
    #define me(x) memset(x,0,sizeof(x))
    namespace IO{
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T> void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; 
        }
        char sr[1<<24],z[20]; int Z,C1=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C1]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C1]=z[Z],--Z);
        }
        IL void wer1()
        {
            sr[++C1]=' ';
        }
        IL void wer2()
        {
            sr[++C1]='
    ';
        }
        template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} 
        template<class T>IL T MAX(T x,T y){return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){return x<y?x:y;}
    };
    using namespace IO;
    const int N=2e6;
    int head[N],l,n,m;
    struct re{
        int a,b;
    }e[N*2];
    IL void arr(int x,int y)
    {
        e[++l].a=head[x];
        e[l].b=y;
        head[x]=l;
    }
    int f[N][2],cnt,fa[N],dfn[N],low[N];
    void dfs(int x,int y)
    {
        dfn[x]=low[x]=++cnt; fa[x]=y;
        f[x][0]=0; f[x][1]=1;
        for (rint u=head[x];u;u=e[u].a)
        {
            int v=e[u].b;
            if (v==y) continue;
            if (low[v]==dfn[x])
            {
                int f0=0,f1=0;
                for (int j=v;j!=x;j=fa[j])
                {
                  int t0=f0,t1=f1;
                  f1=t0+f[j][1];
                  f0=MAX(t0,t1)+f[j][0];
                }
                f[x][0]+=MAX(f0,f1);
                f0=0; f1=0;
                for (int j=v;j!=x;j=fa[j])
                {
                  int t0=f0,t1=f1;
                  f1=t0+f[j][1];
                  f0=MAX(t0,t1)+f[j][0];
                  if (j==v) f1=0;
                }
                f[x][1]+=f0;
            }
            if (!dfn[v])
            { 
              dfs(v,x); low[x]=MIN(low[x],low[v]);
            }
            if (low[v]>dfn[x])
            {
                f[x][0]+=MAX(f[v][0],f[v][1]);
                f[x][1]+=f[v][0];
            }
            mina(low[x],dfn[v]);
        }
    }
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        ios::sync_with_stdio(false);
        cin>>n>>m;
        rep(i,1,m)
        {
            int x,y;
            cin>>x>>y;
            arr(x,y); arr(y,x);
        }
        dfs(1,0);
        cout<<MAX(f[1][0],f[1][1]);
        return 0; 
    }

    2.仙人掌直径

    这个和上一个类似,依旧不用建出圆方树,区分环边和普通边就可以了

    对于环拿个单调队列跑一下 在更新一下每个点到子树的最大值就好了

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for(int i=h;i<=t;i++)
    #define dep(i,t,h) for(int i=t;i>=h;i--)
    #define ll long long
    #define me(x) memset(x,0,sizeof(x))
    namespace IO{
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T> void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; 
        }
        char sr[1<<24],z[20]; int Z,C1=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C1]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C1]=z[Z],--Z);
        }
        IL void wer1()
        {
            sr[++C1]=' ';
        }
        IL void wer2()
        {
            sr[++C1]='
    ';
        }
        template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} 
        template<class T>IL T MAX(T x,T y){return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){return x<y?x:y;}
    };
    using namespace IO;
    const int N=2e6;
    int head[N],l,n,m;
    struct re{
        int a,b;
    }e[N*2];
    IL void arr(int x,int y)
    {
        e[++l].a=head[x];
        e[l].b=y;
        head[x]=l;
    }
    int f[N][2],cnt,fa[N],dfn[N],low[N],ans;
    int a[N];
    re p[N];
    void dfs(int x,int y)
    {
        dfn[x]=low[x]=++cnt; fa[x]=y;
        f[x][0]=f[x][1]=-1;
        for (rint u=head[x];u;u=e[u].a)
        {
            int v=e[u].b;
            if (v==y) continue;
            if (low[v]==dfn[x])
            {
                int cnt=0;
                for (int j=v;j!=x;j=fa[j])
                  a[++cnt]=f[j][0];
                int t=0;
                rep(j,1,cnt) maxa(t,a[j]+MIN(j,cnt-j+1)-1);
                if (t>f[x][0]) f[x][1]=f[x][0],f[x][0]=t;
                else if (t>f[x][1]) f[x][1]=t;
                int len=cnt+1; 
                a[++cnt]=0;
                rep(j,1,cnt) a[cnt+j]=a[cnt];
                cnt*=2;
                int h=1;t=0; p[h]=(re){0,0};
                rep(i,1,cnt)
                {
                    while (h<=t&&(i-p[h].a)>(len/2)) h++;
                    maxa(ans,i+a[i]+p[h].b);
                    while (h<=t&&a[i]-i>=p[t].b) t--;
                    p[++t]=(re){i,a[i]-i};
                }
            }
            if (!dfn[v])
            { 
              dfs(v,x); low[x]=MIN(low[x],low[v]);
            }
            if (low[v]>dfn[x])
            {
                if (f[v][0]>f[x][0])
                {
                    f[x][1]=f[x][0]; f[x][0]=f[v][0];
                } else
                if (f[v][0]>f[x][1]) f[x][1]=f[v][0];
            }
            mina(low[x],dfn[v]);
        }
        maxa(ans,f[x][0]+f[x][1]+2);
        f[x][0]++;
    }
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        while (cin>>n>>m)
        {
        ans=0; me(head); l=0; me(low); me(dfn); me(f); 
        rep(i,1,m)
        {
            int k,x,y;
            cin>>k>>x;
            rep(j,1,k-1)
            {
                cin>>y;
                arr(x,y); arr(y,x);
                x=y;
            }
        }
        dfs(1,0);
        cout<<ans<<endl;
        } 
        return 0; 
    }

    3.求仙人掌两点间最短路

    这个需要建立出真的圆方树

    连边的时候保证了dfn最小的点在方点的上面,而其他点在方点的下面

    定义圆点与方点间的距离为当前点到dfn最小点的距离

    然后查最短路的时候

    如果lca是圆点,那么就是他们之间距离

    如果lca是方点,那么说明是两边儿子(这个可以倍增找)在环上距离+他们到两边的距离

    查找环上两点距离我用的是map维护 $M[i][j]$ 在第i个环上j的前缀和

    #我这个代码在有重边的时候是错的,因为要判父亲的边表而不是点。。(虽然数据并没有重边)

    稍微改一下就可以了

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for(int i=h;i<=t;i++)
    #define dep(i,t,h) for(int i=t;i>=h;i--)
    #define ll long long
    #define me(x) memset(x,0,sizeof(x))
    #define mp make_pair
    namespace IO{
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T> void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; 
        }
        char sr[1<<24],z[20]; int Z,C1=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C1]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C1]=z[Z],--Z);
        }
        IL void wer1()
        {
            sr[++C1]=' ';
        }
        IL void wer2()
        {
            sr[++C1]='
    ';
        }
        template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} 
        template<class T>IL T MAX(T x,T y){return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){return x<y?x:y;}
    };
    using namespace IO;
    const int N=1e5;
    int n,m,q,head[N],l,cnt,color_cnt,fa[N],fa2[N],dfn[N],low[N];
    ll dis[N];
    struct re{
        int a,b,c,from;
        bool t;
    }e[N*2];
    struct re2{
        int a;
        ll b;
    };
    map<pair<int,int>,ll> M;
    struct s2{
      int bz[21][N],dep[N],l,head[N];
      ll p[N],bz2[21][N];
      re e[N*2];
      void ycl()
      {
          rep(i,1,20)
            rep(j,1,n+color_cnt)
              bz[i][j]=bz[i-1][bz[i-1][j]],
            bz2[i][j]=bz2[i-1][j]+bz2[i-1][bz[i-1][j]];
      }
      IL void arr2(int x,int y,int z) 
      {
          e[++l].a=head[x];
          e[l].b=y;
          e[l].c=z;
          head[x]=l;
      }
      void dfs(int x,int y)
      {
          dep[x]=dep[y]+1;
          for (rint u=head[x];u;u=e[u].a)
          {
              int v=e[u].b;
              if (v!=y)
            {
              bz[0][v]=x; bz2[0][v]=e[u].c; 
              dfs(v,x);
            }
          }
      }
      re2 lca(int x,int y)
      {
          if (dep[x]<dep[y]) swap(x,y);
        ll ans=0; 
          dep(i,20,0)
            if (dep[bz[i][x]]>=dep[y]) ans+=bz2[i][x],x=bz[i][x];
          if (x==y) return((re2){x,ans});
        dep(i,20,0)
          if (bz[i][x]!=bz[i][y]) 
            ans+=bz2[i][x]+bz2[i][y],x=bz[i][x],y=bz[i][y];
        ans+=bz2[0][x]+bz2[0][y];
        return (re2){bz[0][x],ans};   
      }
      re2 jump(int x,int y)
      {
          if (dep[x]==y) return((re2){x,0});
          ll ans=0;
          dep(i,20,0)
            if (dep[bz[i][x]]>y) ans+=bz2[i][x],x=bz[i][x];
          ans+=bz2[0][x],x=bz[0][x];
          return (re2){x,ans};
      }
      int query(int x,int y)
      {
          re2 k=lca(x,y);
          if (k.a<=n) return(k.b);
          ll ans=0;
          re2 k1=jump(x,dep[k.a]+1); re2 k2=jump(y,dep[k.a]+1);
          ans=k1.b+k2.b;
        ll len1=abs(M[mp(k.a,k1.a)]-M[mp(k.a,k2.a)]);
        len1=MIN(len1,p[k.a]-len1);
        return ans+len1;
      }
    }S;
    IL void arr(int x,int y,int z)
    {
        e[++l].a=head[x];
        e[l].from=x;
        e[l].b=y;
        e[l].c=z;
        head[x]=l;
    }
    void dfs(int x,int k,int y)
    {
        dfn[x]=low[x]=++cnt; fa[x]=y; fa2[x]=k;
        for (rint u=head[x];u;u=e[u].a)
        {
            int v=e[u].b;
            if (v==y) continue;
            if (!dfn[v])
            {
                dis[v]=dis[x]+e[u].c;
                dfs(v,u,x); mina(low[x],low[v]);
            }
            if (dfn[v]<dfn[x])
            {
                color_cnt++;
                ll len1=0,len2=0;
                for(int j=x;j!=v;j=fa[j]) len2+=e[fa2[j]].c;
                len1=e[u].c;
                S.p[color_cnt]=len1+len2;
                for (int j=x;j!=v;j=fa[j])
                {
                  M[mp(color_cnt,j)]=len1; 
                  S.arr2(color_cnt,j,MIN(len1,len2)),
                  S.arr2(j,color_cnt,MIN(len1,len2));
                  e[fa2[j]].t=1;
                  if (fa2[j]%2==1) e[fa2[j]+1].t=1;
                  else e[fa2[j]-1].t=1;
                  len1+=e[fa2[j]].c; len2-=e[fa2[j]].c;
                }
                e[u].t=1;
                if (u%2==1) e[u+1].t=1; else e[u-1].t=1;
                S.arr2(color_cnt,v,0),S.arr2(v,color_cnt,0);
            }
            mina(low[x],dfn[v]);
        }
    }
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        read(n); read(m); read(q);
        rep(i,1,m)
        {
            int x,y,z;
            read(x); read(y); read(z);
            arr(x,y,z); arr(y,x,z);
        }
        color_cnt=n;
        dfs(1,0,0);
        rep(i,1,l) if (!e[i].t) S.arr2(e[i].from,e[i].b,e[i].c);
        S.dfs(1,0);
        S.ycl();
        rep(i,1,q)
        {
            int x,y;
            read(x); read(y);
            wer(S.query(x,y)); wer2(); 
        }
        fwrite(sr,1,C1+1,stdout);
        return 0;
    }

    数据生成器

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for (int i=h;i<=t;i++)
    #define dep(i,t,h) for (int i=t;i>=h;i--)
    #define me(x) memset(x,0,sizeof(x))
    const int N=10000;
    bool tf[N],now[N];
    int fa[N];
    bool pd(int x,int y)
    {
        if (fa[x]==y||fa[y]==x||x==y) return(0);
        me(tf); tf[0]=1;
        int i;
        for (i=x;i;i=fa[i])
          tf[i]=1;
        for (i=y;tf[i]!=1;i=fa[i])
          if (now[i]) return(0);
        for (int j=x;j!=i;j=fa[j])
          if (now[j]) return(0);
        return(1);
    }
    void cl(int x,int y)
    {
        me(tf); tf[0]=1;
        int i;
        for (i=x;i;i=fa[i])
          tf[i]=1;
        for (i=y;tf[i]!=1;i=fa[i])
          now[i]=1;
        for (int j=x;j!=i;j=fa[j])
          now[j]=1;
    }
    int main()
    {
        freopen("1.in","w",stdout);
        srand(time(0)^size_t(new char));
        int n=30,m=32,q=100;
        cout<<n<<" "<<m<<" "<<q<<endl; 
        rep(i,2,n)
        {
            int x=rand()%(i-1)+1;
            int z=rand()%10+1;
            fa[i]=x;
            cout<<x<<" "<<i<<" "<<z<<endl;
        }
        rep(i,1,m-n+1)
        {
            int x=rand()%n+1,y=rand()%n+1;
            int z=rand()%10+1;
            while (!pd(x,y))
            {
                x=rand()%n+1,y=rand()%n+1;
            }
            cl(x,y);
            cout<<x<<" "<<y<<" "<<z<<endl;
        }
        rep(i,1,q)
        {
            int x=rand()%n+1,y=rand()%n+1;
            cout<<x<<" "<<y<<endl;
        }
        return 0;
    }

     广义圆方树

  • 相关阅读:
    成都磨子桥技工学校 / 数据结构 Challenge 4
    圆桌问题(网络流24题)
    试题库问题(网络流24题)
    [AHOI2005]航线规划
    [AMPPZ2014]The Prices
    方格取数(网络流24题)
    太空飞行计划问题(网络流24题)
    Linux 学习3
    Linux 学习2
    Linux 学习1
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/10042265.html
Copyright © 2020-2023  润新知