【分块】bzoj2957 楼房重建
http://www.cnblogs.com/wmrv587/p/3843681.html
ORZ 分块大爷。思路很神奇也很清晰。
把 块内最值 和 块内有序 两种良好的性质结合起来,非常棒地解决了这个问题。
图中黑色的楼房即为每个块内的“可视序列”,显而易见,在块内它们的K(斜率)是单增的。
由于上图中第一个块的maxK比后面两个块的maxK都要大,所以后两个块对答案没有贡献,这也是显然的。这就是维护maxK的意义所在。
否则,若一个块可以更新maxK的话,则其中的部分楼房是“可见的”,具体来说,就是在那个比之前的maxK要大的楼房的后面的在可视序列中的楼房数。<---请从方链接看原版题解。
另外,并不会像他说的,基本不会T,如果把块大小开得合适。
1 #include<cstdio> 2 #include<algorithm> 3 #include<vector> 4 #include<cmath> 5 #include<cstring> 6 using namespace std; 7 inline double max(const double &a,const double &b){return a>b?a:b;} 8 vector<double>See[320]; 9 double k[100001]; 10 int sz,sum,l[320],r[320],num[100001],n,m,x,y; 11 double maxv[320]; 12 int Res,Num;char C,CH[12]; 13 inline int G() 14 { 15 Res=0;C='*'; 16 while(C<'0'||C>'9')C=getchar(); 17 while(C>='0'&&C<='9'){Res=Res*10+(C-'0');C=getchar();} 18 return Res; 19 } 20 inline void P(int x) 21 { 22 Num=0;if(!x){putchar('0');puts("");return;} 23 while(x>0)CH[++Num]=x%10,x/=10; 24 while(Num)putchar(CH[Num--]+48); 25 puts(""); 26 } 27 void makeblock() 28 { 29 memset(maxv,0,sizeof(maxv)); 30 sz=sqrt((double)n*1.05); 31 for(sum=1;sum*sz<n;sum++) 32 { 33 l[sum]=(sum-1)*sz+1; 34 r[sum]=sum*sz; 35 for(int i=l[sum];i<=r[sum];i++) num[i]=sum; 36 } 37 l[sum]=sz*(sum-1)+1; 38 r[sum]=n; 39 for(int i=l[sum];i<=r[sum];i++) num[i]=sum; 40 } 41 inline void update() 42 { 43 k[x]=(double)y/x; 44 See[num[x]].clear(); 45 maxv[num[x]]=0.0; 46 for(int i=l[num[x]];i<=r[num[x]];i++) 47 if(k[i]>maxv[num[x]]) 48 { 49 maxv[num[x]]=k[i]; 50 See[num[x]].push_back(k[i]); 51 } 52 } 53 inline void query() 54 { 55 int ans=0;double tmp=0.0; 56 for(int i=1;i<=sum;i++) 57 if(!See[i].empty()) 58 { 59 ans+=See[i].end()-upper_bound(See[i].begin(),See[i].end(),tmp); 60 tmp=max(tmp,maxv[i]); 61 } 62 P(ans); 63 } 64 int main() 65 { 66 n=G();m=G();makeblock(); 67 for(int i=1;i<=m;i++){x=G();y=G();update();query();} 68 return 0; 69 }
——The Solution By AutSky_JadeK From UESTC
转载请注明出处:http://www.cnblogs.com/autsky-jadek/