hdu 5929 Basic Data Structure 2016CCPC東北地區大學生程式設計競賽
阿新 • • 發佈:2019-01-08
題目大意:
模擬一個棧,有四種操作:
PUSH x:往棧裡壓入x
POP:丟掉棧頂元素
REVERSE:把棧翻轉過來
QUERY:從棧頂到棧底求nand(與非)
其中0 nand 0=1,1 nand 0=1,0 nand 1=1,1 nand 1=0.
輸出每次的query結果,如果棧是空的輸出Invalid.
題目分析:
棧長度最大為20w,又是雙端的,所以用40w長的陣列和兩個指標模擬很容易實現前三個操作。
關鍵就是第四個。一開始不小心看成了異或,結果wa了一發,然後又想的是用線段樹維護區間的nand值,然後寫了幾個數發現這個運算不滿足結合律,也就是棧頂和棧底反過來的值都是不一樣的~~
看了題解明白了,本題抓住的是任何東西nand 0都為1這一個性質,所以只需要用一個TreeSet(C++裡就是set)來維護最左邊和最右邊的0就可以了,每次查詢的時候,先讀出離棧頂最遠的那個0,然後看看0頂上有沒有東西,如果有東西,不管是什麼,這一段值都為1,如果沒有就為0,那麼就剩下了1串(因為前面一團東西nand 0就是1)求nand,顯然只跟1的奇偶有關係。這裡還有個坑導致wa了一發,就是0頂上沒東西的時候,就只需要看0下面1的個數,而不是+1。
然後還有一個問題就是那個set的end()返回的迭代器是最大值後面的那個。。。。這塊又wa了一發。
//source:2016CCPC東北地區大學生程式設計競賽 - 重現賽
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IN(s) freopen(s,"r",stdin)
#define OUT(s) freopen(s,"w",stdout)
int t,n,x,ans,cnt;
int q[400010];
char op[10];
set<int> s;
int main() {
//IN("5929.in");
scanf("%d",&t);
int ca=1;
while(t--) {
printf("Case #%d:\n", ca++);
scanf("%d ",&n);
int l=200005,r=200006;//雙端對列從中點開始
s.clear();
bool d=0;//0 for left,1 for right
while(n--) {
scanf("%s",op);
if(op[0]=='P' && op[1]=='U') { //PUSH x
scanf("%d",&x);
if(d==0) {
q[l]=x;
if(x==0)
s.insert(l);
l--;
}
else {
q[r]=x;
if(x==0)
s.insert(r);
r++;
}
}
else if(op[0]=='P' && op[1]=='O') { //POP
if(d==0) {
if(q[l+1]==0)
s.erase(l+1);
l++;
}
else {
if(q[r-1]==0)
s.erase(r-1);
r--;
}
}
else if(op[0]=='Q') { //QUERY
if(r-l<=1)
printf("Invalid.\n");
else {
if(s.empty())
printf("%d\n", (r-l+1)&1);
else {
set<int>::iterator i = s.end();
i--;
//printf("Debug: begin=%d,end=%d,l=%d,r=%d,d=%d\n",*s.begin(),*i,l,r,d);
if(d==0) {
if(*i-l>1)
printf("%d\n",(r-*i)&1);
else
printf("%d\n", (r-*i+1)&1);
}
else {
if(r-*s.begin()>1)
printf("%d\n",(*s.begin()-l)&1);
else
printf("%d\n",(*s.begin()-1-l)&1);
}
}
}
}
else //REVERSE
d=!d;
}
}
}