HDU1540 樹狀陣列+二分
阿新 • • 發佈:2019-01-28
題意:
有一串1,現在 D i 表示將第i個位置的點修改成0,R表示把最晚修改的一個數恢復成0,Q i表示詢問包含第i個數在內的最長1串的長度
思路:
網上的程式碼大多用線段樹維護連續區間的左右端點,本蒟篛並不是很理解。
我的方法是,兩次二分,分別把第i個數的左部分最長1串的長度和第i個數右部分最長1串的長度求出,
其中二分的判斷方式是區間和是否為區間長度,區間和用樹狀陣列維護。
特別注意的是:一個已經被摧毀的村莊可能會再次被摧毀!
AC程式碼如下(二分程式碼極醜,希望諒解)
/* 最怕一生碌碌無為,還說平凡難能可貴。 */ #include<bits/stdc++.h> #define INF 50010 using namespace std; int n,m; int e[INF],cnt,pos,a[INF]; int lowbit(int x){return x&(-x);} void add(int x,int y) { while(x<=n+1) { e[x]+=y; x+=lowbit(x); } } int getsum(int x) { int sum=0; while(x>0) { sum+=e[x]; x-=lowbit(x); } return sum; } int getmaxlen(int x) { if(a[x]!=1)return 0; int leftpos,rightpos; int left=1,right=x,mid; while(left<right) { mid=left+right>>1; if(getsum(x)-getsum(mid-1)<x-mid+1) left=mid+1; else right=mid; } leftpos=left; left=x,right=n+1; while(left<right) { mid=left+right>>1; if(getsum(mid)-getsum(x-1)<mid-x+1) right=mid; else left=mid+1; } rightpos=left; return rightpos-leftpos; } int main() { //freopen("in.in","r",stdin); ios::sync_with_stdio(false);cin.tie(NULL); char s[2]; while(cin>>n>>m) { memset(e,0,sizeof(e)); stack<int>q; for(int i=1;i<=n;i++) add(i,1),a[i]=1; cnt=pos=0; while(m--) { cin>>s; if(s[0]=='D') { cin>>pos; q.push(pos); if(a[pos]==1) { a[pos]=0; add(pos,-1); } } if(s[0]=='R') { if(!q.empty()) { pos=q.top(); q.pop(); if(a[pos]==0) { a[pos]=1; add(pos,1); } } } if(s[0]=='Q') { cin>>pos; cout<<getmaxlen(pos)<<endl; } } } }