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;
}
时间: 2024-10-01 22:12:13

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

从《楼房重建》出发浅谈一类使用线段树维护前缀最大值的算法

首先需要申明的是,真的是浅谈,因为我对这个算法的认识还是非常低的. 既然是从<楼房重建>出发,那么当然是先看看这道题: [清华集训2013]楼房重建 bzoj 链接 题意简述: 有 \(n\) 栋楼,第 \(i\) 栋的高度为 \(H_i\),也就是说第 \(i\) 栋楼可以抽象成一条两端点为 \((i, 0)\) 和 \((i, H_i)\) 的线段. 初始时 \(H_i\) 均为 \(0\),要支持动态修改单点的 \(H_i\). 每次询问从 \(O(0, 0)\) 点可以看到多少栋楼房.

CodeForces - 1263E(线段树维护前缀和最值)

题意 https://vjudge.net/problem/CodeForces-1263E 您要设计一个只有一行的打字机,这一行的长度是无限大,一开始可以认为每个字符都是空.您的打字机有一个光标只指向一个字符,一开始指向最左侧的字符. 使用者有三种操作: L 将光标向左移一格(当光标已经在最左侧时,忽略这次操作) R 将光标向右移一格 一个小写字符或者'(',')' 将当前字符替换为给定字符 您需要在每次操作后,判断这一行是否是合法括号序列(例如 (ahakioi) 就是合法的,(ige))(

BZOJ 2725: [Violet 6]故乡的梦 最短路+线段树

2725: [Violet 6]故乡的梦 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 678  Solved: 204[Submit][Status][Discuss] Description Input Output Sample Input 6 7 1 2 1 2 3 1 3 4 2 4 5 1 5 6 1 1 3 3 4 6 3 1 6 4 1 2 1 3 4 3 6 5 Sample Output 7 6 Infinity 7 HINT

2016shenyang-1002-HDU5893-List wants to travel-树链剖分+线段树维护不同区间段个数

肯定先无脑树链剖分,然后线段树维护一段区间不同个数,再维护一个左右端点的费用. 线段树更新,pushDown,pushUp的时候要注意考虑链接位置的费用是否相同 还有就是树链剖分操作的时候,维护上一个更新的位置的费用. 总之就是出现区间合并,就考虑总数是否要减一 好想不好写 //场上根本写不完啊 1 /*--------------------------------------------------------------------------------------*/ 2 3 #inc

[BZOJ 1018] [SHOI2008] 堵塞的交通traffic 【线段树维护联通性】

题目链接:BZOJ - 1018 题目分析 这道题就说明了刷题少,比赛就容易跪..SDOI Round1 Day2 T3 就是与这道题类似的..然而我并没有做过这道题.. 这道题是线段树维护联通性的经典模型. 我们线段树的一个节点表示一个区间的联通性,有 6 个 bool 值,表示这个区间的 4 个角上的点之间的联通性. 然后用两个子区间的联通性和两个子区间之间的连边情况合并出整个区间的联通性. 修改某条边时,先在边的数组中修改,然后从这条边所在的点的线段树叶子开始向上 Update . 询问两

CodeForces 343D 线段树维护dfs序

给定一棵树,初始时树为空 操作1,往某个结点注水,那么该结点的子树都注满了水 操作2,将某个结点的水放空,那么该结点的父亲的水也就放空了 操作3,询问某个点是否有水 我们将树进行dfs, 生成in[u], 访问结点u的时间戳,out[u],离开结点u的时间戳 每个结点的in值对应在线段树中的区间的一点 那么对于操作1, 只要将区间[in[u],out[u]] 的值都改为1, 但是如果区间[in[u],out[u]] 原先存在为0的点,那么父区间肯定是空的,这个操作不能 改变父区间的状态,所以需要

Codeforces GYM 100114 D. Selection 线段树维护DP

D. Selection Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Description When selecting files in an application dialog, Vasya noted that he can get the same selection in different ways. A simple mouse click selects a sing

Subsequence Count 2017ccpc网络赛 1006 dp+线段树维护矩阵

Problem Description Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries on the string.There are two types of queries:1. Flipping the bits (i.e., changing all 1 to 0 and 0 to 1) between l and r (inclusive).2. Counting the

HDU 6155 Subsequence Count 线段树维护矩阵

Subsequence Count Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others) Problem Description Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries on the string. There are two types of querie