BZOJ2957:楼房重建 分块
Feb 03, 2015 07:47:25 AM
逗逼分块,写完题解结果被吞QoQ.直接贴代码.
#include<cstdio> #include<cstring> #include<cctype> #include<iostream> #include<algorithm> #include<cmath> using namespace std; typedef double f2; typedef long long LL; namespace Fio{ inline int getc(){ static const int L=1<<15;static char buf[L],*fS=buf,*fT=buf; if(fS==fT){fT=(fS=buf)+fread(buf,1,L,stdin);if(fS==fT)return EOF;} return*fS++; } inline bool digit(char c){return c>='0'&&c<='9';} template<typename T>inline void Get(T&x){ int c;while(!digit(c=getc()));x=c-'0';while(digit(c=getc()))x=(x<<1)+(x<<3)+c-'0'; } char buf[600010],*o=buf; template<typename T>inline void print(T x){ static int stk[100];int top=0; if(!x)*o++=48;else{for(;x;x/=10)stk[++top]=x%10;for(int i=top;i>=1;--i)*o++=48+stk[i];} *o++='\n'; } inline void final(){fwrite(buf,1,o-buf,stdout);} } #define N 100010 int begin[510],end[510],bel[N]; double res[N]; struct Stack{ int top; double s[510]; Stack():top(0){} inline void upd(int l,int r){ top=0; for(int i=l;i<=r;++i)if(!top||res[i]>s[top])s[++top]=res[i]; } inline int getans(const f2&x){ if(!top||s[top]<=x)return 0; int L=1,R=top,mid; while(L<R){ mid=(L+R)>>1; if(s[mid]>x)R=mid;else L=mid+1; }return top-L+1; } }S[510]; int main(){ int n,m;Fio::Get(n),Fio::Get(m);register int i,j; int persize=sqrt(n),nums=0; for(i=1;i*persize<=n;++i)begin[++nums]=(i-1)*persize+1,end[nums]=i*persize; if(n%persize)++nums,begin[nums]=(nums-1)*persize+1,end[nums]=n; for(i=1;i<=nums;++i)for(j=begin[i];j<=end[i];++j)bel[j]=i; for(i=1;i<=n;++i)res[i]=0; int x,y,ret;f2 Max; while(m--){ Fio::Get(x),Fio::Get(y); res[x]=(f2)y/x; S[bel[x]].upd(begin[bel[x]],end[bel[x]]); for(ret=0,Max=0,i=1;i<=nums;++i){ ret+=S[i].getans(Max); if(S[i].top&&S[i].s[S[i].top]>Max)Max=S[i].s[S[i].top]; } Fio::print(ret); } return Fio::final(),0; }
BZOJ3834:[Poi2014]Solar Panels 分块
Jan 08, 2015 07:34:34 AM
思路:
首先若\(x\)可以作为答案,必定满足\(b/i-(a-1)/i\geq{1},d/i-(c-1)/i\geq{1}\).
注意到单独的\(v/i\)是只有\(O(\sqrt{n})\)块的,我们可以单独算出对于\(a,b\)满足条件的块,以及对于\(c,d\)满足条件的块.
接下来我们只需求出 两部分的最大交点即可,我们可以在\(O(\sqrt{n})\)的时间内线性扫描得到.
#include<cstdio> #include<cstring> #include<climits> #include<iostream> #include<algorithm> using namespace std; int l[2][100000],r[2][100000],blks[2]; int main(){ int T;cin>>T;int a,b,c,d,last,ans;register int i,j,k; while(T--){ scanf("%d%d%d%d",&a,&b,&c,&d);blks[0]=blks[1]=0; for(i=1;i<a;i=last+1){ last=min(b/(b/i),(a-1)/((a-1)/i)); if(b/i-(a-1)/i>=1)l[0][++blks[0]]=i,r[0][blks[0]]=last; } l[0][++blks[0]]=a,r[0][blks[0]]=b; for(i=1;i<c;i=last+1){ last=min(d/(d/i),(c-1)/((c-1)/i)); if(d/i-(c-1)/i>=1)l[1][++blks[1]]=i,r[1][blks[1]]=last; } l[1][++blks[1]]=c,r[1][blks[1]]=d, j=1; for(ans=0,i=1;i<=blks[0];++i){ while(j<=blks[1]&&r[1][j]<l[0][i])++j; for(k=j;k<=blks[1]&&l[1][k]<=r[0][i];++k)ans=max(ans,min(r[0][i],r[1][k])); } printf("%d\n",ans); }return 0; }