补题:2019牛客暑期多校训练营(第一场)

比赛链接

彻彻底底坑了队友= =


A. Equivalent Prefixes

【考场上的想法】

从前往后扫,对于当前的一位置$i$,判断加入后是否equivalent,相当于判断$j=max\{j\text{|}a[j]<a[i],j<i\}$、$k=max\{k\text{|}b[k]<b[i],k<i\}$是否相等

这可以用二分+线段树懒标记解决:

每次区间赋值,是给$a[i],b[i]$对应的线段树的区间$[j+1,i]$分别赋$i$(若赋值,则默认了$j=k$),表示这段区间中最小的数的下标为$i$

然后对于新的$i$,可以二分找出$j$、$k$

总复杂度$O(n(logn)^2)$

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=100005;

int n;
int a[N],b[N];

struct SegTree
{
int sz;
int t[N<<2],tag[N<<2];

void Init(int x)
{
    sz=x;
    for(int i=1;i<(sz<<1);i++)
        t[i]=tag[i]=0;
}

inline void Push(int k)
{
    if(!tag[k])
        return;
    
    t[k]=tag[k];
    tag[k]=0;
    if(k>=sz)
        return;
    tag[k<<1]=tag[k<<1|1]=t[k];
}

inline void Add(int k,int l,int r,int a,int b,int x)
{
    Push(k);
    if(a>r || b<l)
        return;
    if(a>=l && b<=r)
    {
        tag[k]=x;
        Push(k);
        return;
    }
    int mid=(a+b)>>1;
    Add(k<<1,l,r,a,mid,x);
    Add(k<<1|1,l,r,mid+1,b,x);
}

inline int Query(int k,int p,int a,int b)
{
    Push(k);
    if(a==b)
        return t[k];
    int mid=(a+b)>>1;
    if(p<=mid)
        return Query(k<<1,p,a,mid);
    else
        return Query(k<<1|1,p,mid+1,b);
}
}ta,tb;

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
            scanf("%d",&b[i]);
        
        int sz=1;
        while(sz<n)
            sz<<=1;
        
        ta.Init(sz),tb.Init(sz);
        
        int ans=1;
        ta.Add(1,1,1,1,sz,1);
        tb.Add(1,1,1,1,sz,1);
        for(int i=2;i<=n;i++)
        {
            int pa,pb;
            int left=1,right=i-1,mid;
            while(left<right)
            {
                mid=(left+right)>>1;
                if(a[ta.Query(1,mid,1,sz)]<a[i])
                    left=mid+1;
                else
                    right=mid;
            }
            if(a[left]>a[i])
                left--;
            pa=left;
            
            left=1,right=i-1;
            while(left<right)
            {
                mid=(left+right)>>1;
                if(b[tb.Query(1,mid,1,sz)]<b[i])
                    left=mid+1;
                else
                    right=mid;
            }
            if(b[left]>b[i])
                left--;
            pb=left;
            
            if(pa!=pb)
                break;
            ans=i;
            
            ta.Add(1,pa+1,i,1,sz,i);
            tb.Add(1,pb+1,i,1,sz,i);
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

【正常做法】


猜你喜欢

转载自www.cnblogs.com/LiuRunky/p/Nowcoder_2019_Multischool_Round1.html