(线段树操作)
https://codeforces.com/contest/1187/problem/D
题意:选取a序列的一段【l,r】将选中的区间按非降排序。问能否经过若干次操作后形成b序列;
分析:b序列的数的总类及各个类的数目一定要与a序列相同;
对b的每个位置的值,找到与之相同的a序列中还没有被用的位置nowpos,然后判断1到nowpos的最小值是否等于b序列的当前值,再将该位置修改为无效值;
若有一步不成功则输出NO,否者YES;
#include<bits/stdc++.h> using namespace std; const int M=3e5+5; const int inf=0x3f3f3f3f; int tree[M<<2],a[M],b[M],aa[M],bb[M],ll[M]; vector<int>pos[M]; void up(int root){ tree[root]=min(tree[root<<1],tree[root<<1|1]); } void build(int root,int l,int r){ if(l==r){ tree[root]=a[l]; return ; } int midd=(l+r)>>1; build(root<<1,l,midd); build(root<<1|1,midd+1,r); up(root); } int query(int L,int R,int root,int l,int r){ if(L<=l&&r<=R){ return tree[root]; } int midd=(l+r)>>1; int ans=inf; if(L<=midd) ans=min(ans,query(L,R,root<<1,l,midd)); if(R>midd) ans=min(ans,query(L,R,root<<1|1,midd+1,r)); return ans; } void update(int nowpos,int x,int root,int l,int r){ if(l==r){ tree[root]=x; return ; } int midd=(l+r)>>1; if(midd>=nowpos) update(nowpos,x,root<<1,l,midd); else update(nowpos,x,root<<1|1,midd+1,r); up(root); } int main(){ int t; scanf("%d",&t); while(t--){ int n; scanf("%d",&n); for(int i=0;i<=n;i++){ pos[i].clear(); ll[i]=0; } for(int i=1;i<=n;i++){ scanf("%d",&a[i]); pos[a[i]].push_back(i); aa[i]=a[i]; } for(int i=1;i<=n;i++){ scanf("%d",&b[i]); bb[i]=b[i]; } sort(aa+1,aa+1+n); sort(bb+1,bb+1+n); int flag=0; for(int i=1;i<=n;i++){ if(aa[i]!=bb[i]){ flag=1; break; } } if(flag){ puts("NO"); continue; } build(1,1,n); /* for(int i=1;i<=n*2;i++) cout<<tree[i]<<" ";*/ for(int i=1;i<=n;i++){ int ch=b[i]; // cout<<ch<<endl; if(flag) continue; int cur_pos=pos[ch][ll[ch]++]; if(ch!=query(1,cur_pos,1,1,n)){ flag=1; } // cout<<"!!"<<endl; update(cur_pos,inf,1,1,n); } if(flag) puts("NO"); else puts("YES"); } return 0; }