BZOJ 2957 楼房重建 (分块)
题解:分块,然后暴力维护每一块上升序列,注意是不是最长上升序列,二分查找第二块中大于第一块的最后一个上升序列中的数。
注意:每一块的大小不要用√n会T掉的,把块的大小设为500-600都可以(T了一页了)。或者你用线段树去写。
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <map> #include <queue> #include <vector> #include <cstring> #include <iomanip> #include <set> #include<ctime> //#include<unordered_map> //CLOCKS_PER_SEC #define se second #define fi first #define ll long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define Pii pair<int,int> #define Pli pair<ll,int> #define ull unsigned long long #define pb push_back #define fio ios::sync_with_stdio(false);cin.tie(0) const int N=1e5+10; const ull base=163; const int INF=0x3f3f3f3f; using namespace std; int h[N]; struct node { int top,sta[600]; }p[600]; bool cmp(int x,int y){ if(!y)return h[x]>0; return 1LL*y*h[x]>1LL*x*h[y]; } int main(){ int n,m; scanf("%d%d",&n,&m); int sz=550; for(int i=1;i<=m;i++){ int x;scanf("%d",&x); scanf("%d",&h[x]); int l=x/sz*sz; int r=min(n+1,(x/sz+1)*sz); p[x/sz].top=0; for(int i=l;i<r;i++){ if(cmp(i,p[x/sz].sta[p[x/sz].top])){ p[x/sz].sta[++p[x/sz].top]=i; } } int last=0,ans=0; for(int i=0;i<=(n)/sz;i++){ int l=1,r=p[i].top; int op=0; while (l<=r) { int mid=(l+r)>>1; if(cmp(p[i].sta[mid],last)){ r=mid-1; op=mid; } else{ l=mid+1; } } if(op){ last=p[i].sta[p[i].top]; ans+=p[i].top-op+1; } } printf("%d\n",ans); } return 0; }