BZOJ 3669 [Noi2014]魔法森林

本文介绍了一种利用链剖树(LCT)优化算法解决特定类型图论问题的方法。通过对边权转化为点权,按边的属性排序,并使用LCT维护连通性和边权,实现对最优解的高效求解。文章详细阐述了算法步骤,包括如何判断新加入边的影响,以及如何通过删除或保留边来保持最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=3669

题解

将一个a-b,权值为c的边看成a-e-b,其中a,b权值为0,e的权值为c,这样就把边权变成了点权。

首先将所有边按照 Ai A i 排序,用LCT维护点和边的连通情况,边权为 Bi B i

考虑新加入一条从 x x y,权值为 ai,bi a i , b i 的边。显然,如果这条边对 1 1 n的答案有影响,那么答案就可以对 ai+max(1nBi) a i + max ( 1 → n 的 B i ) min min 。如果这条边对答案没有影响,那么答案必定已经 前述式子,对前述式子更新不会对答案有任何影响( ai a i 不是最小的, + + 号后面值的是相同的)。

  1. 如果x y y 不连通,那么加入这条边不会对答案产生不利的影响。
  2. 如果x y y 连通,这个时候分两种情况考虑。
    1. x y y Bi最大值 bi ≤ b i ,加入这条边必定不会使 1 1 n的边权最大值变小,因此选择不加入。

      • x x y Bi B i 最大值 >bi > b i ,此时删去 x x y中边权最大的一个,必定不会使 1 1 n的边权最大值变大,因此可以这样操作。
      • 可以证明,通过上述操作,得出的解一定是最优的。

        代码

        #include <cstdio>
        #include <algorithm>
        
        int read()
        {
          int x=0,f=1;
          char ch=getchar();
          while((ch<'0')||(ch>'9'))
            {
              if(ch=='-')
                {
                  f=-f;
                }
              ch=getchar();
            }
          while((ch>='0')&&(ch<='9'))
            {
              x=x*10+ch-'0';
              ch=getchar();
            }
          return x*f;
        }
        
        const int maxn=50000;
        const int maxm=100000;
        const int maxk=maxn+maxm;
        const int inf=0x3f3f3f3f;
        
        struct node
        {
          node *son[2],*fa,*pos;
          int self,val,rev;
        };
        
        node tree[maxk+10];
        
        namespace lct
        {
          int isroot(node *x)
          {
            if(x->fa==NULL)
              {
                return 1;
              }
            return !((x->fa->son[0]==x)||(x->fa->son[1]==x));
          }
        
          int t(node *x)
          {
            return x->fa->son[1]==x;
          }
        
          int pushdown(node *x)
          {
            if(x->rev)
              {
                x->rev=0;
                std::swap(x->son[0],x->son[1]);
                if(x->son[0]!=NULL)
                  {
                    x->son[0]->rev^=1;
                  }
                if(x->son[1]!=NULL)
                  {
                    x->son[1]->rev^=1;
                  }
              }
            return 0;
          }
        
          int updata(node *x)
          {
            int l=(x->son[0]==NULL)?0:x->son[0]->val,r=(x->son[1]==NULL)?0:x->son[1]->val;
            x->val=std::max(x->self,std::max(l,r));
            x->pos=(x->self>=std::max(l,r))?x:((l>r)?x->son[0]->pos:x->son[1]->pos);
            return 0;
          }
        
          int rotate(node *x)
          {
            node *f=x->fa;
            pushdown(f);
            pushdown(x);
            int k=t(x);
            if(!isroot(f))
              {
                f->fa->son[t(f)]=x;
              }
            x->fa=f->fa;
            f->fa=x;
            if(x->son[k^1]!=NULL)
              {
                x->son[k^1]->fa=f;
              }
            f->son[k]=x->son[k^1];
            x->son[k^1]=f;
            updata(x);
            updata(f);
            return 0;
          }
        
          int splay_root(node *x)
          {
            while(!isroot(x))
              {
                node *f=x->fa;
                if(isroot(f))
                  {
                    rotate(x);
                  }
                else if(t(f)==t(x))
                  {
                    rotate(f);
                    rotate(x);
                  }
                else
                  {
                    rotate(x);
                    rotate(x);
                  }
              }
            pushdown(x);
            return 0;
          }
        
          int access(node *x)
          {
            node *y=NULL;
            while(x!=NULL)
              {
                splay_root(x);
                x->son[1]=y;
                if(y!=NULL)
                  {
                    y->fa=x;
                  }
                updata(x);
                y=x;
                x=y->fa;
              }
            return 0;
          }
        
          int makeroot(node *x)
          {
            access(x);
            splay_root(x);
            x->rev^=1;
            return 0;
          }
        
          int link(node *x,node *y)
          {
            makeroot(x);
            x->fa=y;
            return 0;
          }
        
          int cut(node *x,node *y)
          {
            makeroot(x);
            access(y);
            splay_root(y);
            y->son[0]=x->fa=NULL;
            updata(y);
            return 0;
          }
        
          node* find(node *x)
          {
            access(x);
            splay_root(x);
            while(x->son[0]!=NULL)
              {
                x=x->son[0];
                pushdown(x);
              }
            return x;
          }
        
          int check(node *x,node *y)
          {
            return find(x)==find(y);
          }
        
          node* getmax(node *x)
          {
            splay_root(x);
            int v=x->val;
            while(x!=NULL)
              {
                if(x->self==v)
                  {
                    return x;
                  }
                if((x->son[0]!=NULL)&&(x->son[0]->val==v))
                  {
                    x=x->son[0];
                  }
                else
                  {
                    x=x->son[1];
                  }
                pushdown(x);
              }
            return 0;
          }
        
          node* getpn(node *x,int op)
          {
            splay_root(x);
            x=x->son[op];
            pushdown(x);
            while(x->son[op^1]!=NULL)
              {
                x=x->son[op^1];
                pushdown(x);
              }
            return x;
          }
        
          int check_link(node *x,node *y,node *e)
          {
            if(check(x,y))
              {
                makeroot(x);
                access(y);
                splay_root(y);
                if(y->val>e->self)
                  {
                    node *d=y->pos;
                    node *p=getpn(d,0),*q=getpn(d,1);
                    cut(d,p);
                    cut(d,q);
                  }
                else
                  {
                    return 0;
                  }
              }
            link(e,x);
            link(e,y);
            return 0;
          }
        
          int getmax(node *x,node *y)
          {
            makeroot(x);
            access(y);
            splay_root(y);
            return y->val;
          }
        }
        
        struct edge
        {
          int x,y,a,b;
        
          bool operator <(const edge &other) const
          {
            if(a==other.a)
              {
                return b<other.b;
              }
            return a<other.a;
          }
        };
        
        edge e[maxm+10];
        int n,m;
        
        int main()
        {
          n=read();
          m=read();
          for(int i=1; i<=m; ++i)
            {
              e[i].x=read();
              e[i].y=read();
              e[i].a=read();
              e[i].b=read();
            }
          std::sort(e+1,e+m+1);
          for(int i=1; i<=n; ++i)
            {
              tree[i].son[0]=tree[i].son[1]=tree[i].fa=NULL;
              tree[i].self=tree[i].val=tree[i].rev=0;
            }
          int ans=inf;
          node *start=&tree[1],*end=&tree[n];
          for(int i=1; i<=m; ++i)
            {
              tree[i+n].son[0]=tree[i+n].son[1]=tree[i+n].fa=NULL;
              tree[i+n].self=tree[i+n].val=e[i].b;
              tree[i+n].rev=0;
              node *l=&tree[e[i].x],*r=&tree[e[i].y],*ed=&tree[i+n];
              lct::check_link(l,r,ed);
              if(lct::check(start,end))
                {
                  ans=std::min(ans,e[i].a+lct::getmax(start,end));
                }
            }
          printf("%d\n",(ans==inf)?-1:ans);
          return 0;
        }
        
资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 华为移动服务(Huawei Mobile Services,简称 HMS)是一个全面开放的移动服务生态系统,为企业和开发者提供了丰富的工具和 API,助力他们构建、运营和推广应用。其中,HMS Scankit 是华为推出的一款扫描服务 SDK,支持快速集成到安卓应用中,能够提供高效且稳定的二维码和条形码扫描功能,适用于商品扫码、支付验证、信息获取等多种场景。 集成 HMS Scankit SDK 主要包括以下步骤:首先,在项目的 build.gradle 文件中添加 HMS Core 库和 Scankit 依赖;其次,在 AndroidManifest.xml 文件中添加相机访问和互联网访问权限;然后,在应用程序的 onCreate 方法中调用 HmsClient 进行初始化;接着,可以选择自定义扫描界面或使用 Scankit 提供的默认扫描界面;最后,实现 ScanCallback 接口以处理扫描成功和失败的回调。 HMS Scankit 内部集成了开源的 Zxing(Zebra Crossing)库,这是一个功能强大的条码和二维码处理库,提供了解码、生成、解析等多种功能,既可以单独使用,也可以与其他扫描框架结合使用。在 HMS Scankit 中,Zxing 经过优化,以更好地适应华为设备,从而提升扫描性能。 通常,ScanKitDemoGuide 包含了集成 HMS Scankit 的示例代码,涵盖扫描界面的布局、扫描操作的启动和停止以及扫描结果的处理等内容。开发者可以参考这些代码,快速掌握在自己的应用中实现扫码功能的方法。例如,启动扫描的方法如下: 处理扫描结果的回调如下: HMS Scankit 支持所有安卓手机,但在华为设备上能够提供最佳性能和体验,因为它针对华为硬件进行了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值