SDUSTOJ 1796 哆啦A梦的军队(线段树维护前缀位置)

Description

在2050年机器人战争爆发,聪明的机器猫为了帮助大雄打赢这场战 争,从自己口袋里掏出了机器人战棋,每一个战棋都可以成为一名战士,哆啦A梦决定给他们整整队,哆啦A梦发现第 i 个位置的战士编号为 Ai(显然 A 是一个排列)。经过计算,哆啦A梦发现,让第 i 个位置的战士编号为 Bi 时,他的军队可以发挥出最大的战斗力(保证 B 也是一个排列)。
哆啦A梦可以发出指令来改变战士们的排列顺序,每一次,他都会报出一个整数 i(1≤i<n)。如果排在第 i 个位置的战士编号大于第 i+1 个位置的战士,那么这两个战士会交换顺序,否则这一个命令将会被忽略。
现在哆啦A梦希望他的军队能够发挥出最强大的战斗力,于是他想要知道是否存在一种指令序列,使得战士们可以按照排列 B 的方式排列。
但是因为战士数目实在是太多,哆啦A梦一时间也没有看出答案。于是他用时间机器带来了你——21世纪最著名的民间科学家来帮他计算这个问题的答案。

Input

输入数据第一行包含一个正整数 n(n<=100000)。

接下来两行每行 n 个正整数,分别描述排列 A和排列 B。

Output

对于每组数据,如果存在这样的指令序列,输出“YES”,否则输出“NO”(引号不输出,请注意大小写)。

Sample Input

3
2 3 1
2 1 3
3
2 1 3
3 1 2

Sample Output

YES
NO

思路:这道题是山科第三届校赛的H题,我们队过的最后一道题,由于太弱,想了大概一个小时左右才初步有了思路
就是先建一棵max的线段树,数组a和b分别记录交换之前和交换之后数值的下标
然后从大到小循环,每次判断该数值是否向右移动(或者不移动),如果成立就询问线段树初始位置在该元素右边的
值移动后所在的最左端的位置。当前数值移动后的位置必须小于查询的结果。
然后每个值都更新线段树,将初始位置的值更新为交换之后的位置。
然后同理从小到大循环,每次判断向左移动,询问最右端的位置就好了
/* ***********************************************
Author        :devil
Created Time  :2016/4/26 13:11:52
************************************************ */
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <stdlib.h>
using namespace std;
const int N=100005;
int n,a[N],b[N],tree[N<<2];
void build1(int node,int l,int r)
{
    if(l==r)
    {
        tree[node]=N;
        return ;
    }
    int m=(l+r)>>1;
    build1(node<<1,l,m);
    build1(node<<1|1,m+1,r);
    tree[node]=min(tree[node<<1],tree[node<<1|1]);
}
void update1(int node,int l,int r,int p)
{
    if(l==r)
    {
        tree[node]=b[p];
        return ;
    }
    int m=(l+r)>>1;
    if(a[p]<=m) update1(node<<1,l,m,p);
    else update1(node<<1|1,m+1,r,p);
    tree[node]=min(tree[node<<1],tree[node<<1|1]);
}
int query1(int node,int l,int r,int p)
{
    if(l>=p) return tree[node];
    int m=(l+r)>>1,ans;
    ans=query1(node<<1|1,m+1,r,p);
    if(p<=m) ans=min(ans,query1(node<<1,l,m,p));
    return ans;
}
void build2(int node,int l,int r)
{
    if(l==r)
    {
        tree[node]=0;
        return ;
    }
    int m=(l+r)>>1;
    build2(node<<1,l,m);
    build2(node<<1|1,m+1,r);
    tree[node]=max(tree[node<<1],tree[node<<1|1]);
}
void update2(int node,int l,int r,int p)
{
    if(l==r)
    {
        tree[node]=b[p];
        return ;
    }
    int m=(l+r)>>1;
    if(a[p]<=m) update2(node<<1,l,m,p);
    else update2(node<<1|1,m+1,r,p);
    tree[node]=max(tree[node<<1],tree[node<<1|1]);
}
int query2(int node,int l,int r,int p)
{
    if(r<=p) return tree[node];
    int m=(l+r)>>1,ans;
    ans=query2(node<<1,l,m,p);
    if(p>m) ans=max(ans,query2(node<<1|1,m+1,r,p));
    return ans;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(~scanf("%d",&n))
    {
        int x,flag=1;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&x);
            a[x]=i;
        }
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&x);
            b[x]=i;
        }
        build1(1,1,n);
        for(int i=n; i>0; i--)
        {
            if(a[i]<=b[i]&&b[i]>query1(1,1,n,a[i]))
            {
                flag=0;
                break;
            }
            update1(1,1,n,i);
        }
        if(!flag)
        {
            printf("NO\n");
            continue;
        }
        build2(1,1,n);
        for(int i=1; i<=n; i++)
        {
            if(a[i]>=b[i]&&b[i]<query2(1,1,n,a[i]))
            {
                flag=0;
                break;
            }
            update2(1,1,n,i);
        }
        if(!flag) printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}

 

posted on 2016-04-26 13:12  恶devil魔  阅读(373)  评论(0编辑  收藏  举报

导航