Codeforces 1187 D. Subarray Sorting —— 线段树,贪心

This way

题意:

现在有两个数组,并且你每次可以做一个操作:选择一个区间,并且排序。
问你对上面这个数组做一些操作之后是否能得到下面这个数组。

题解:

那么如果每次选的区间大小为2,那么就像是一个冒泡排序了,将一个大的值依次向后传并且保持其他的值顺序不变。
那么我们只需要从后往前枚举一遍b数组,然后查看a数组对应的bi的值的最后一个位置到n的最大值是否有一个数大于他。如果有就不行,因为他没有办法交换到后面去。如果行那就将这个值去掉,因为它已经排好了。我用线段树维护最大值。

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int a[N],b[N],mx[N*4];
queue<int>Q[N];
void update(int l,int r,int root,int p,int v){
    if(l==r){
        mx[root]=v;
        return ;
    }
    int mid=l+r>>1;
    if(mid>=p)
        update(l,mid,root<<1,p,v);
    else
        update(mid+1,r,root<<1|1,p,v);
    mx[root]=max(mx[root<<1],mx[root<<1|1]);
}
int query(int l,int r,int root,int ql,int qr){
    if(l>=ql&&r<=qr)
        return mx[root];
    int mid=l+r>>1,ans=0;
    if(mid>=ql)
        ans=query(l,mid,root<<1,ql,qr);
    if(mid<qr)
        ans=max(ans,query(mid+1,r,root<<1|1,ql,qr));
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),update(1,n,1,i,a[i]);
        for(int i=n;i;i--)
            Q[a[i]].push(i);
        for(int i=1;i<=n;i++)
            scanf("%d",&b[i]);
        int f=0;
        for(int i=n;i;i--){
            if(Q[b[i]].empty()){
                f=1;
                break;
            }
            int p=Q[b[i]].front();
            Q[b[i]].pop();
            if(query(1,n,1,p,n)>b[i]){
                f=1;
                break;
            }
            update(1,n,1,p,0);
        }
        for(int i=1;i<=n;i++)while(!Q[i].empty())Q[i].pop();
        if(f)printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/107406963