防线 Defence

Posted coder-cjh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了防线 Defence相关的知识,希望对你有一定的参考价值。

这一题写的时候也是懵逼的,想到了大概思路

首先的操作肯定是处理出以 ii 为结尾的最长连续上升序列

那么接下来最朴素的算法可以达到 O(N^2)

有没有更快的做法?

考虑我们枚举的是前 ii 项,那么有些很明显无用的东西被重复枚举了

如果 a[i]>a[j] 并且 g[i]<=g[j] ,那么选 i肯定没有选 j 优,所以考虑用一个

set来维护这个东西,注意细节

#include<bits/stdc++.h>
using namespace std;
set<pair<int,int> > q;
int n,a[200005],h[200005],g[200005];
int main()
    int t;
    scanf("%d",&t);
    while(t--)
       scanf("%d",&n);g[n+1]=0;
       for(int i=1;i<=n;i++) scanf("%d",&a[i]);
       for(int i=1;i<=n;i++) h[i]=a[i]>a[i-1]?h[i-1]+1:1;//预处理
       for(int i=n;i>=1;i--) g[i]=a[i]<a[i+1]?g[i+1]+1:1;
       q.clear();
       int ans=1;q.insert(make_pair(a[1],h[1]));//用pair维护
       for(int i=2;i<=n;i++)
         pair<int,int> x(a[i],h[i]);
         set<pair<int,int> > :: iterator it=q.lower_bound(x);//找到满足条件的
         if(it!=q.begin())
            --it;ans=max(ans,(*it).second+g[i]);//更新答案
            if((*it).second>=x.second)continue;//如果已经可以比i更优,直接跳过i
         
         q.erase(x);q.insert(x);//抹去原本存在的x,重新插入,以便找到位置 
         it=++q.find(x);
         while(it!=q.end())
          if((*it).second<=x.second&&(*it).first>x.first)q.erase(it);//找到合适的位置插入,并删除不可能的答案 
          else break;
          ++it;//往后迭代 
         
         q.insert(x);//插入,再次更新 
       
       printf("%d\n",ans);
    

 

以上是关于防线 Defence的主要内容,如果未能解决你的问题,请参考以下文章

防线修建 bzoj 2300

cogs 547:[HAOI2011] 防线修建

bzoj2300HAOI2011防线修建

BZOJ2300[HAOI2011]防线修建 set维护凸包

BZOJ 2300 2300: [HAOI2011]防线修建 (动态凸包+set)

BZOJ 2300 HAOI2011 防线修建