Solution -「營業」「CF 527C」Glass Carving
阿新 • • 發佈:2021-07-08
Description
Link.
有一個塊 \(n\times m\) 的矩形,有 \(q\) 次操作,每次把矩形橫 / 豎著切一刀,問切完後的最大矩形面積。
Solution
一個不同於大多數人、總時間複雜度 \(\mathcal{O}(n\log_{2}n)\),每次回答 \(\mathcal{O}(\alpha(n))\) 的做法,瓶頸在排序。
顯然答案是最大行列相乘。首先我們把詢問離線,然後逆序處理。你發現這相當於把切開變成了合併,最大值不降,於是可以直接維護。
具體來說就是維護兩個並查集,分別是行和列,然後再維護集合內元素個數,然後就直接合並。
#include<bits/stdc++.h> using namespace std; typedef long long ll; inline ll read() { ll x=0,f=0; char ch=getchar(); while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+(ch&15),ch=getchar(); return f?-x:x; } const int N=200100; signed main() { int m=read(),n=read(),q=read(); static int far[N],fac[N],szr[N],szc[N]; iota(far+1,far+m+1,1); iota(fac+1,fac+n+1,1); for(int i=1;i<=m;++i) szr[i]=1; for(int i=1;i<=n;++i) szc[i]=1; auto findr=[&](int x) {while(x!=far[x]) x=far[x]=far[far[x]]; return x;}; auto findc=[&](int x) {while(x!=fac[x]) x=fac[x]=fac[fac[x]]; return x;}; auto merger=[&](int x,int y) {x=findr(x),y=findr(y); (x!=y)&&(szr[y]+=szr[x],szr[x]=0,far[x]=y);}; auto mergec=[&](int x,int y) {x=findc(x),y=findc(y); (x!=y)&&(szc[y]+=szc[x],szc[x]=0,fac[x]=y);}; static int op[N],X[N]; vector<int> hx,vx; for(int i=1; i<=q; ++i) { char Op[4]; scanf("%s",Op); op[i]=Op[0]=='H'; X[i]=read(); (op[i])&&(X[i]=n-X[i]); (op[i])&&(hx.push_back(X[i]),1); (!op[i])&&(vx.push_back(X[i]),1); } sort(hx.begin(),hx.end()); sort(vx.begin(),vx.end()); hx.insert(hx.begin(),0); vx.insert(vx.begin(),0); hx.push_back(n); vx.push_back(m); for(unsigned int i=1; i<hx.size(); ++i) for(int j=hx[i-1]+2; j<=hx[i]; ++j) mergec(j-1,j); for(unsigned int i=1; i<vx.size(); ++i) for(int j=vx[i-1]+2; j<=vx[i]; ++j) merger(j-1,j); ll mxr=0,mxc=0; for(int i=1; i<=m; ++i) mxr=max(mxr,(ll)szr[findr(i)]); for(int i=1; i<=n; ++i) mxc=max(mxc,(ll)szc[findc(i)]); vector<ll> ans; ans.push_back(mxr*mxc); for(int i=q; i>1; --i) { if(op[i]) mergec(X[i]+1,X[i]),mxc=max(mxc,(ll)szc[findc(X[i])]); else merger(X[i],X[i]+1),mxr=max(mxr,(ll)szr[findr(X[i])]); ans.push_back(mxr*mxc); } reverse(ans.begin(),ans.end()); for(ll x:ans) printf("%lld\n",x); return 0; }