Origami(想法摺紙 樹狀陣列)
阿新 • • 發佈:2018-12-04
原題: 位元組跳動冬令營網路賽B
題意:
有一段繩子,上面有1~n個點,你可以在一個地方摺疊這個繩子,問最後能否折成給出的結果
解析:
上張圖說明一切
所以只需要判斷上面部分有沒有交叉,下面部分有沒有交叉即可
這個用樹狀陣列,判斷每一段中的左端點數量是否等於右端點數量
#include<bits/stdc++.h>
using namespace std;
#define LL long long
int pos[1000009];
bool vis[1000009];
int zero[1000009];
int one[1000009];
void add(int *ar,int pos,int n){
while(pos<=n){
ar[pos]++;
pos+=pos&(-pos);
}
}
int query(int *ar,int pos){
int ans=0;
while(pos>0){
ans+=ar[pos];
pos-=pos&(-pos);
}
return ans;
}
int main(){
int t;scanf("%d",&t);
while(t--){
int n; scanf("%d",&n);
for(int i=1;i<=n;i++){
int tmp;scanf("%d",&tmp);
pos[tmp]=i;
}
for(int i=1;i<=n;i++)vis[i]=0;
int cant=0;
for(int i=1;i<=n;i++)zero[i]=one[i]=0;
for(int i=1;i<n;i+=2){
if(i+1>n)break ;
int x=pos[i],y=pos[i+1];
if(x>y)swap(x,y);
if(vis[x]||vis[y]){cant=1;break;}
add(zero,x,n);
add(one,y,n);
}
if(cant){
printf("No\n");
continue;
}
for(int i=1;i<n;i+=2){
if(i+1>n)break;
int x=pos[i],y=pos[i+1];
if(x>y)swap(x,y);
int z=query(zero,y-1)-query(zero,x);
int o=query(one,y-1)-query(one,x);
if(z!=o){
cant=1;break;
}
}
if(cant){
printf("No\n");
continue;
}
for(int i=1;i<=n;i++)vis[i]=0;
cant=0;
for(int i=1;i<=n;i++)zero[i]=one[i]=0;
for(int i=2;i<n;i+=2){
if(i+1>n)break;
int x=pos[i],y=pos[i+1];
if(x>y)swap(x,y);
if(vis[x]||vis[y]){cant=1;break;}
add(zero,x,n);
add(one,y,n);
}
if(cant){
printf("No\n");
continue;
}
for(int i=2;i<n;i+=2){
if(i+1>n)break;
int x=pos[i],y=pos[i+1];
if(x>y)swap(x,y);
int z=query(zero,y-1)-query(zero,x);
int o=query(one,y-1)-query(one,x);
if(z!=o){
cant=1;break;
}
}
if(cant){
printf("No\n");
continue;
}
printf("Yes\n");
}
}