zoukankan      html  css  js  c++  java
  • bzoj 2151 种树 —— 思路+链表

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2151

    先都放进堆里取最大的,但选了一个就不能选它两边的,所以可能不是最优,要有“反悔”的措施;

    可以取出一个后把它两边的位置 l,r 在链表中删除,然后再加入一个元素 a[x] = a[l] + a[r] - a[x],如果日后选了这个元素,就表示“反悔”了,当初不选 x 而是同时选了两边的(同时选比只选一个或不选更优);

    而此时这个 x 的两边实际上是 l-1 和 r+1,因为其实选的是 l,r,这点用链表删除和查询就可以体现,更何况两边也可能被这样合并过;

    再记一个 vis 表示这个位置从堆里取出时能不能选了,和链表的删除一致;

    因为每次取出都会增加一个选择的位置,所以取出 m 次即可。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int const xn=2e5+5;
    int n,m,a[xn],pr[xn],nt[xn],ans;
    bool vis[xn];
    struct N{
      int v,id;
      bool operator < (const N &y) const
      {return v<y.v;}
    };
    priority_queue<N>q;
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    void del(int x){nt[pr[x]]=nt[x]; pr[nt[x]]=pr[x];}
    int main()
    {
      n=rd(); m=rd();
      for(int i=1;i<=n;i++)
        {
          a[i]=rd();
          q.push((N){a[i],i});
        }
      if(n<2*m){puts("Error!"); return 0;}
      for(int i=2;i<n;i++)pr[i]=i-1,nt[i]=i+1;
      pr[1]=n; nt[1]=2; pr[n]=n-1; nt[n]=1;
      for(int i=1;i<=m;i++)
        {
          int x=q.top().id,w=q.top().v; q.pop();
          while(vis[x])x=q.top().id,w=q.top().v,q.pop();
          int l=pr[x],r=nt[x]; ans+=w;
          del(l); del(r); vis[l]=1; vis[r]=1; a[x]=a[l]+a[r]-w;
          q.push((N){a[x],x});
        }
      printf("%d
    ",ans);
      return 0;
    }
  • 相关阅读:
    sublime there are no packages for installation
    linux 安装php扩展mbstring
    生成器表达式和列表推导式
    send()和next()
    迭代器生成器
    装饰器
    函数随笔
    Django进阶
    数据结构与算法入门
    MySQL必会
  • 原文地址:https://www.cnblogs.com/Zinn/p/9818305.html
Copyright © 2011-2022 走看看