【推导】【线段树】hdu5929 Basic Data Structure

题意:

维护一个栈,支持以下操作:

从当前栈顶加入一个0或者1;

从当前栈顶弹掉一个数;

将栈顶指针和栈底指针交换;

询问a[top] nand a[top-1] nand ... nand a[bottom]的值。

nand是这样定义的:

∙∙ 0 nand 0 = 1 
∙∙ 0 nand 1 = 1 
∙∙ 1 nand 0 = 1 
∙∙ 1 nand 1 = 0

关键是要发现性质,任何数nand 0,都会变成1。反复nand上1的话,则值会交替变化。

所以假设当前栈顶在左侧,只需要找到最右侧的0的位置,然后按照其右侧1的数量的奇偶性输出零或者一即可(如果最右侧的0在最左端,则其右侧有奇数个1就输出1,否则输出零。如果最右侧的零不在最左端,则其右侧有奇数个1就输出零,否则输出1)。

栈顶在右侧的情况同理。

用线段树维护。

#include<cstdio>
#include<cstring>
using namespace std;
bool hav[400005<<2];
int a[400005];
int T,m,n,e[2];
void update(int p,int v,int rt,int l,int r){
if(l==r){
if(v==0){
hav[rt]=1;
}
else{
hav[rt]=0;
}
return;
}
int m=(l+r>>1);
if(p<=m){
update(p,v,rt<<1,l,m);
}
else{
update(p,v,rt<<1|1,m+1,r);
}
hav[rt]=(hav[rt<<1] || hav[rt<<1|1]);
}
int find1(int rt=1,int l=1,int r=n){
if(l==r){
return l;
}
int m=(l+r>>1);
if(hav[rt<<1]){
return find1(rt<<1,l,m);
}
else{
return find1(rt<<1|1,m+1,r);
}
}
int find2(int rt=1,int l=1,int r=n){
if(l==r){
return l;
}
int m=(l+r>>1);
if(hav[rt<<1|1]){
return find2(rt<<1|1,m+1,r);
}
else{
return find2(rt<<1,l,m);
}
}
int main(){
//freopen("h.in","r",stdin);
int x;
bool dir=0;
char op[10];
scanf("%d",&T);
memset(a,-1,sizeof(a));
for(int zu=1;zu<=T;++zu){
printf("Case #%d:\n",zu);
scanf("%d",&m);
e[0]=m;
e[1]=m+1;
n=2*m;
for(int i=1;i<=m;++i){
scanf("%s",op);
if(op[2]=='S'){
scanf("%d",&x);
if(!dir){
a[e[0]]=x;
update(e[0],x,1,1,n);
--e[0];
}
else{
a[e[1]]=x;
update(e[1],x,1,1,n);
++e[1];
}
}
else if(op[2]=='P'){
if(!dir){
++e[0];
a[e[0]]=-1;
update(e[0],-1,1,1,n);
}
else{
--e[1];
a[e[1]]=-1;
update(e[1],-1,1,1,n);
}
}
else if(op[2]=='V'){
dir^=1;
}
else{
if(e[0]==e[1]-1){
puts("Invalid.");
continue;
}
if(hav[1]){
if(!dir){
int p=find2();
if(p==e[0]+1){
puts((e[1]-p-1)%2==1 ? "1" : "0");
}
else{
puts((e[1]-p-1)%2==1 ? "0" : "1");
}
}
else{
int p=find1();
if(p==e[1]-1){
puts((p-e[0]-1)%2==1 ? "1" : "0");
}
else{
puts((p-e[0]-1)%2==1 ? "0" : "1");
}
}
}
else{
puts((e[1]-e[0]-1)%2==1 ? "1" : "0");
}
}
}
memset(a,-1,sizeof(int)*(n+1));
memset(hav,0,sizeof(bool)*(n*4+1));
}
return 0;
}
上一篇:随记,C#修饰符访问级别


下一篇:Java RMI 简单示例