题面
现在有一块玻璃,是长方形的(w 毫米× h 毫米),现在要对他进行切割。
切割的方向有两种,横向和纵向。每一次切割之后就会有若干块玻璃被分成两块更小的玻璃。在切割之后玻璃不会被移动。
现在想知道每次切割之后面积最大的一块玻璃是多少。
2≤w,h≤200000, 1≤n≤200000
分析
这种一根根的线,放在线段树里面,害得我又以为是扫描线。
其实,是可以模拟的吧?
正难则反,倒着做,先预处理出所有线左右两边的线及距离,可顺便得到最大的纵向距离和横向距离,这就是最后一次切割后的答案。
倒着删线,每次删掉一根线只增大它附近两根线的距离,判断一下删掉这根线后最大距离是否增大。
注意别把w和h看反了。WA了好几发TAT
代码
#include<bits/stdc++.h> using namespace std; #define N 200020 #define ll long long ll W,H,n,p; char op[3]; ll ans[N],mxh,mxl; ll rem[N],tmp[N],x[N],y[N]; struct email { ll pre,nxt; ll len; }h[N],l[N]; int main() { scanf("%d%d%d",&W,&H,&n); for(ll i=1;i<=n;i++) { scanf("%s%d",op,&tmp[i]); if(op[0]=='H')y[tmp[i]]=1,rem[i]=1; else x[tmp[i]]=1; } y[0]=y[H]=1;p=0;l[H].nxt=W; for(ll i=0;i<=H;i++) if(y[i])l[i].len=i-p,l[i].pre=p,l[p].nxt=i,p=i,mxl=max(mxl,l[i].len); x[0]=x[W]=1;p=0;h[W].nxt=W; for(ll i=0;i<=W;i++) if(x[i])h[i].len=i-p,h[i].pre=p,h[p].nxt=i,p=i,mxh=max(mxh,h[i].len); ans[n]=mxh*mxl; for(ll i=n;i>=2;i--) { if(rem[i]) { ll now=tmp[i]; l[l[now].pre].nxt=l[now].nxt;l[l[now].nxt].pre=l[now].pre; l[l[now].nxt].len+=l[now].len;mxl=max(mxl,l[l[now].nxt].len); } else { ll now=tmp[i]; h[h[now].pre].nxt=h[now].nxt;h[h[now].nxt].pre=h[now].pre; h[h[now].nxt].len+=h[now].len;mxh=max(mxh,h[h[now].nxt].len); } ans[i-1]=mxl*mxh; } for(ll i=1;i<=n;i++)printf("%lld ",ans[i]); return 0; }
又送样例
input1 2 2 1 V 1 output1 2 input2 5 15 10 H 8 H 9 V 1 H 2 H 6 H 4 H 1 V 2 H 13 V 3 output2 40 40 32 24 24 24 24 18 12 8
第一组也太黑了,浪费我五个积分TAT