此为犟种的胜利,我太菜了呜呜呜\sout{此为犟种的胜利,我太菜了呜呜呜}此为犟种的胜利,我太菜了呜呜呜
分析:
首先发现的性质是如果是beautiful的话,他如果要继续拓展的话,只能是最小值-1 或者 最大值+1,那么我们可以固定最小值(iii),每次去找它最大能拓展到哪里(记为rrr),那么最小值iii对答案的贡献就是r−i+1r-i+1r−i+1,([i],[i,i+1]....[i,i+1,r][i],[i,i+1]....[i,i+1,r][i],[i,i+1]....[i,i+1,r]),那么只需要解决最后一个问题了,怎么找他最多能拓展到哪里?我们可以查询即将插入这个数位置的逆序对个数和顺序对个数,如果他在两个数组中的逆序对个数或者顺序对个数不一样那么就说明他们的相对位置是不同的,那么就是不可以插入的,这个可以用线段树做到,按照位置建线段树,因为插入的数是递增的所以找到的位置比他小的个数就是顺序对个数,找到的位置比他大的就是逆序对个数
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using i128 = __int128;
constexpr int maxn = 1e5+10;
int n;
int v[2][maxn];
int pos[2][maxn];
int tree0[maxn<<2],tree1[maxn<<2];
void pushup(int p,int l,int r,int *tree){
tree[p]=tree[p*2]+tree[p*2+1];
}
void update(int p,int l,int r,int x,int num,int *tree){
if(l==r){
if(num==1) tree[p]=1;
else tree[p]=0;
return;
}
int mid = (l+r)>>1;
if(x<=mid) update(p*2,l,mid,x,num,tree);
else update(p*2+1,mid+1,r,x,num,tree);
pushup(p,l,r,tree);
}
int query(int p,int l,int r,int x,int y,int *tree){
if (x > r || y < l) return 0;
if(x<=l&&r<=y){
if(x==y) return(tree[p]>0);
else return tree[p];
}
int mid = (l+r)>>1;
int ans = 0;
if(x<=mid) ans+=query(p*2,l,mid,x,y,tree);
if(y>mid) ans+=query(p*2+1,mid+1,r,x,y,tree);
return ans;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i = 0;i<2;++i){
for(int j = 1;j<=n;++j){
cin>>v[i][j];
pos[i][v[i][j]] = j;
}
}
i64 ans = 0;
for(int i = 1,r = 1;i<=n;++i){
update(1,1,n,pos[0][i],1,tree0);
update(1,1,n,pos[1][i],1,tree1);
while(r+1<=n){
update(1,1,n,pos[0][r+1],1,tree0);
update(1,1,n,pos[1][r+1],1,tree1);
if(query(1,1,n,1,pos[0][r+1],tree0)!=query(1,1,n,1,pos[1][r+1],tree1)||query(1,1,n,pos[0][r+1],n,tree0)!=query(1,1,n,pos[1][r+1],n,tree1)){
update(1,1,n,pos[0][r+1],-1,tree0);
update(1,1,n,pos[1][r+1],-1,tree1);
break;
}
++r;
}
ans+=r-i+1;
update(1,1,n,pos[0][i],-1,tree0);
update(1,1,n,pos[1][i],-1,tree1);
}
cout<<ans<<"\n";
return 0;
}