UVA 1471(p242)----Defense Lines

#include<bits/stdc++.h>
#define debu
using namespace std;
const int maxn=2*1e5+50;
const int INF=1e9+50;
struct point
{
    int w,g;
    point(int a=0,int b=0):w(a),g(b) {}
    bool operator < (const point& rhs) const
    {
        return w<rhs.w;
    }
};
int n;
set<point> s;
int a[maxn],f[maxn],g[maxn];
void prepare()
{
    a[0]=INF;
    for(int i=0; i<=n; i++) f[i]=1;
    for(int i=n; i>=1; i--)
        if(a[i-1]<a[i]) f[i-1]+=f[i];
    for(int i=0; i<=n; i++) g[i]=1;
    for(int i=1; i<=n; i++)
        if(a[i]>a[i-1]) g[i]+=g[i-1];
}
void solve()
{
    int ans=1;
    point tmp(a[1],g[1]);
    s.insert(tmp);
    for(int i=2; i<=n; i++)
    {
        point tmp(a[i],g[i]);
        set<point>::iterator it=s.lower_bound(tmp);
        int flag=1;
        if(it!=s.begin())
        {
            it--;
            int len=(*it).g;
            ans=max(ans,len+f[i]);
            if((*it).g>=g[i]) flag=0;
        }
        if(flag)
        {
            s.insert(tmp);
            it=s.find(tmp);
            it++;
            while(it!=s.end()&&(*it).g<=g[i]&&(*it).w>=a[i]) s.erase(it++);
        }
    }
    printf("%d\n",ans);
}
int main()
{
#ifdef debug
    freopen("in.in","r",stdin);
#endif // debug
    int t;
    scanf("%d",&t);
    while(t--)
    {
        s.clear();
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        prepare();
        solve();
    }
    return 0;
}

题目地址:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4217

题解:f[i]表示以i开始的最长递增连续序列,g[i]表示以i结尾的最长递增连续序列,则ans=max{g[j]+f[i]}(j<=i)。如枚举i,j,时间无法承受。所以只枚举i,快速找一个j,使得a[j]<a[i],,j<=i且g[j]应尽量大。注意到当a[i]>a[j]且g[i]<=g[j]时,g[i]一定不为最优,应舍去。set中元素有序且自带lower_bound,所以使用set。每次检测是否应该插入元素a[i],若可以,则插入后不断检测插入后位置的元素是否应该舍去。

你可能感兴趣的:(UVA 1471(p242)----Defense Lines)