题解 洛希极限
小蒟蒻写了一下午加一上午,确实是只菜鸡呢
首先考虑有哪些点可以更新当前点,盗张图(出处)
看起来能更新这个点的范围是左上角的矩形,但实际上只有一行一列
因为其它点先跳到这一行一列中再跳到当前点显然更优
于是可以过subtask2
然后决策点从矩形变成了一行一列,就可以对每行每列维护一个单调队列来优化
但弹单调队列时需要找一个最远范围,在每个位置都枚举所有矩形就炸上天了,所以要预处理
考虑预处理一个 \(left[i][j], up[i][j]\) 为行/列上可以更新这个点的最远位置
然后怎么预处理呢?
我们想尽可能避免矩形的重复覆盖问题
于是题解神仙思路:并查集
先拎出一行来单独考虑,发现若矩形已经排过序了,我们可以用类似这题的思路来跳过已经被覆盖过的地方
但注意一个细节:并查集仅用于维护点的覆盖关系,不维护权值
然后直接对每个矩形枚举其中一维更新的复杂度是假的,变成了 \(O(q\sum h)\)
题解神仙解决方案:(以更新left为例)
当我们更新left时,先将所有矩形按 \(y_1\) 排序,按列建立并查集,然后从大到小枚举列,每列从上往下更新
若枚举到一列满足这一列中(在当前矩形内的)第一个点已经被覆盖了且这一列在当前矩形内已经没有没被覆盖的点了,就可以直接break掉了
正确性在于因为矩形是按 \(y_1\) 排序的,所以若一列已经被完全覆盖了那它前面的列也一定被完全覆盖了
于是总复杂度为 \(O(nm+q)\)
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 2010
#define ll long long
#define fir first
#define sec second
#define make make_pair
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m, q;
const ll mod=1e9+7;
inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}
namespace force{
int maxn;
ll ans;
pair<int, ll> mp[N][N];
struct rec{int x1, y1, x2, y2; inline void build(int a, int b, int c, int d){x1=a; y1=b; x2=c; y2=d;}}r[500010];
inline bool operator & (rec a, pair<int, ll> b) {
return a.x1<=b.fir&&b.fir<=a.x2 && a.y1<=b.sec&&b.sec<=a.y2;
}
void solve() {
maxn=ans=0;
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) mp[i][j]=make(1, 1);
for (int i=1,a,b,c,d; i<=q; ++i) {
a=read(); b=read(); c=read(); d=read();
r[i].build(a, b, c, d);
}
for (int i=1; i<=n; ++i) {
for (int j=1; j<=m; ++j) {
for (int k=1; k<i; ++k) {
for (int l=1; l<j; ++l) {
for (int t=1; t<=q; ++t) if (r[t]&make(i, j) && r[t]&make(k, l)) {
if (mp[i][j].fir<mp[k][l].fir+1) mp[i][j]=make(mp[k][l].fir+1, mp[k][l].sec);
else if (mp[i][j].fir==mp[k][l].fir+1) md(mp[i][j].sec, mp[k][l].sec);
break;
}
}
}
maxn=max(maxn, mp[i][j].fir);
}
}
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) if (mp[i][j].fir==maxn) md(ans, mp[i][j].sec);
printf("%d %lld\n", maxn, ans);
}
}
namespace task1{
int dsu[N][N], val[N][N], nxt[N][N], left[N][N], up[N][N], f[N][N];
ll g[N][N];
inline int find1(int now, int p) {return dsu[now][p]==p?p:dsu[now][p]=find1(now, dsu[now][p]);}
inline int find2(int p, int now) {return dsu[p][now]==p?p:dsu[p][now]=find2(dsu[p][now], now);}
struct rec{int x1, y1, x2, y2; inline void build(int a, int b, int c, int d){x1=a; y1=b; x2=c; y2=d;}}r[500010];
inline bool cmp1(rec a, rec b) {return a.y1<b.y1;}
inline bool cmp2(rec a, rec b) {return a.x1<b.x1;}
struct que{
int l=1, r=0; ll buc[N];
struct node{int val, pos; ll cnt; inline void build(int v, int p, ll c){val=v; pos=p; cnt=c;}}q[N];
void del(int line) {while (l<=r && q[l].pos<line) buc[q[l].val]=(buc[q[l].val]-q[l].cnt)%mod, ++l;}
int qmax() {return l<=r?q[l].val:0;}
int qcnt() {return (buc[q[l].val]+mod)%mod;}
void add(int val, int pos, ll cnt) {
while (l<=r && q[r].val<val) buc[q[r].val]=(buc[q[r].val]-q[r].cnt)%mod, --r;
q[++r].build(val, pos, cnt); buc[val]=(buc[val]+cnt)%mod;
}
void clear() {while (l<=r) buc[q[l].val]=(buc[q[l].val]-q[l].cnt)%mod, ++l; l=1; r=0;}
void show() {for (int i=l; i<=r; ++i) cout<<q[i].val<<','<<q[i].pos<<','<<q[i].cnt<<' '; cout<<endl;}
}qc[N], qr[N];
void solve() {
for (int i=1,a,b,c,d; i<=q; ++i) {
a=read(); b=read(); c=read(); d=read();
r[i].build(a, b, c, d);
}
#if 0
sort(r+1, r+q+1, cmp1);
for (int i=1; i<n; ++i) {
// cout<<"i: "<<i<<endl;
for (int j=1; j<=m; ++j) dsu[j]=val[j]=j, nxt[j]=j+1;
for (int j=1; j<=q; ++j) if (r[j].x1<=i&&i+1<=r[j].x2) {
// cout<<"j: "<<j<<endl;
int s=nxt[find(r[j].y1)], t=r[j].y2, bel=find(s);
val[bel]=r[j].y1;
// cout<<"st: "<<s<<' '<<t<<endl;
for (int now=s,f; now<=t; ++now) {
f=find(now);
if (bel!=f) {
dsu[f]=bel;
nxt[bel]=nxt[f];
}
}
}
for (int j=1; j<=m; ++j) left[i+1][j]=val[find(j)];
}
#elif 0
sort(r+1, r+q+1, cmp1);
// cout<<"r: "; for (int i=1; i<=q; ++i) cout<<r[i].x1<<','<<r[i].y1<<','<<r[i].x2<<','<<r[i].y2<<' '; cout<<endl;
for (int i=1; i<=m; ++i) left[1][i]=i;
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) dsu[i][j]=val[i][j]=j, nxt[i][j]=j+1;
for (int i=1; i<=q; ++i) {
for (int j=r[i].x1; j<r[i].x2; ++j) {
// cout<<"y1: "<<r[i].y1<<endl;
// cout<<"dsu: "<<find1(j, r[i].y1)<<endl;
int s=nxt[j][find1(j, r[i].y1)], t=r[i].y2;
while (s<=t && val[j][find1(j, s)]!=find1(j, s)) s=nxt[j][find1(j, s)];
if (s>t) continue;
int bel=find1(j, s);
// cout<<"ij: "<<i<<' '<<j<<' '<<s<<endl;
// cout<<"bel: "<<bel<<endl;
val[j][bel]=r[i].y1;
for (int now=s,f; now<=t; now=nxt[j][f]) {
// cout<<"now: "<<now<<endl;
f=find1(j, now);
if (val[j][now]) {nxt[j][bel]=nxt[j][f]; continue;}
if (bel!=f) {
dsu[j][f]=bel;
nxt[j][bel]=nxt[j][f];
}
}
// cout<<"nxt: "<<nxt[j][bel]<<endl;
if (s>1) nxt[j][find1(j, s-1)]=nxt[j][bel];
}
// if (i==8) {
// cout<<"val"<<endl;
// for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<val[i][find1(i, j)]<<' '; cout<<endl;}
// }
}
for (int i=1; i<n; ++i) for (int j=1; j<=m; ++j) left[i+1][j]=val[i][find1(i, j)];
#endif
cout<<"left"<<endl;
for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<left[i][j]<<' '; cout<<endl;}
#if 0
sort(r+1, r+q+1, cmp2);
for (int i=1; i<=n; ++i) up[i][1]=i;
for (int i=1; i<m; ++i) {
for (int j=1; j<=n; ++j) dsu[j]=val[j]=j, nxt[j]=j+1;
for (int j=1; j<=q; ++j) if (r[j].y1<=i&&i+1<=r[j].y2) {
int s=nxt[find(r[j].x1)], t=r[j].x2, bel=find(s);
val[bel]=r[j].x1;
for (int now=s,f; now<=t; ++now) {
f=find(now);
if (bel!=f) {
dsu[f]=bel;
nxt[bel]=nxt[f];
}
}
}
for (int j=1; j<=m; ++j) up[j][i+1]=val[find(j)];
}
#elif 0
sort(r+1, r+q+1, cmp2);
// cout<<"r: "; for (int i=1; i<=q; ++i) cout<<r[i].x1<<','<<r[i].y1<<','<<r[i].x2<<','<<r[i].y2<<' '; cout<<endl;
for (int i=1; i<=n; ++i) up[i][1]=i;
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) dsu[i][j]=val[i][j]=i, nxt[i][j]=i+1;
for (int i=1; i<=q; ++i) {
for (int j=r[i].y1; j<r[i].y2; ++j) {
// cout<<"x1: "<<r[i].x1<<endl;
// cout<<"dsu: "<<find2(r[i].x1, j)<<endl;
// int f=find2(r[i].x1, j);
// while (nxt[f][j]<=r[i].x2 && up[nxt[f][j]][j]) nxt[f][j]=nxt[find2(nxt[f][j], j)][j];
int s=nxt[find2(r[i].x1, j)][j], t=r[i].x2;
while (s<=t && val[find2(s, j)][j]!=find2(s, j)) s=nxt[find2(s, j)][j];
if (s>t) continue;
int bel=find2(s, j);
// cout<<"ij: "<<i<<' '<<j<<' '<<s<<endl;
// cout<<"bel: "<<bel<<endl;
val[bel][j]=r[i].x1;
for (int now=s,f; now<=t; now=nxt[f][j]) {
// cout<<"now: "<<now<<endl;
f=find2(now, j);
if (val[f][j]) {cout<<"continue"<<endl; nxt[bel][j]=nxt[f][j]; continue;}
// cout<<"f: "<<f<<endl;
if (bel!=f) {
dsu[f][j]=bel;
nxt[bel][j]=nxt[f][j];
}
}
// cout<<"nxt: "<<nxt[bel][j]<<endl;
if (s>1) {
nxt[find2(s-1, j)][j]=nxt[bel][j];
// cout<<"lst: "<<find2(s-1, j)<<endl;
}
}
// cout<<"dsu3: "<<find2(3, 4)<<endl;
// if (i==3) {
// cout<<"val"<<endl;
// for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<val[find2(i, j)][j]<<' '; cout<<endl;}
// }
}
for (int i=1; i<=n; ++i) for (int j=1; j<m; ++j) up[i][j+1]=val[find2(i, j)][j];
#endif
cout<<"up"<<endl;
for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<up[i][j]<<' '; cout<<endl;}
int ans1=0; ll ans2=0;
for (int i=1; i<=n; ++i) {
for (int j=1; j<=m; ++j) {
// cout<<"ij: "<<i<<' '<<j<<endl;
// cout<<"del: "<<left[i][j]<<endl;
qr[i-1].del(left[i][j]);
qc[j-1].del(up[i][j]);
int maxn=max(qr[i-1].qmax(), qc[j-1].qmax());
ll cnt=0;
if (maxn) {
if (qr[i-1].qmax()==maxn) md(cnt, qr[i-1].qcnt()); //, cout<<"qrcnt: "<<qr[i-1].qcnt()<<endl;
if (qc[j-1].qmax()==maxn) md(cnt, qc[j-1].qcnt()); //, cout<<"qccnt: "<<qc[j-1].qcnt()<<endl;
// if (i==3 && j==4) qr[i-1].show();
f[i][j]=maxn+1; g[i][j]=cnt;
}
else f[i][j]=1, g[i][j]=1;
// printf("f[%d][%d]=%d, g[%d][%d]=%lld\n", i, j, f[i][j], i, j, g[i][j]);
// cout<<"max: "<<maxn<<' '<<cnt<<endl;
ans1=max(ans1, f[i][j]);
if (j>1) qr[i-1].add(f[i-1][j-1], j-1, g[i-1][j-1]);
}
for (int j=1; j<=m; ++j) qc[j].add(f[i][j], i, g[i][j]);
}
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) if (f[i][j]==ans1) md(ans2, g[i][j]);
printf("%d %lld\n", ans1, ans2);
for (int i=0; i<=n; ++i) qr[i].clear();
for (int i=0; i<=m; ++i) qc[i].clear();
}
}
namespace task{
int dsu[N][N], siz[N][N], nxt[N][N], left[N][N], up[N][N], f[N][N];
ll g[N][N];
inline int find(int now, int p) {return dsu[now][p]==p?p:dsu[now][p]=find(now, dsu[now][p]);}
inline void uni(int now, int a, int b) {
int f1=find(now, a), f2=find(now, b);
if (f1==f2) return ;
if (siz[now][f2]>siz[now][f1]) swap(f1, f2);
siz[now][f1]+=siz[now][f2]; nxt[now][f1]=max(nxt[now][f1], nxt[now][f2]);
dsu[now][f2]=f1;
}
struct rec{int x1, y1, x2, y2; inline void build(int a, int b, int c, int d){x1=a; y1=b; x2=c; y2=d;}}r[500010];
inline bool cmp1(rec a, rec b) {return a.y1<b.y1;}
inline bool cmp2(rec a, rec b) {return a.x1<b.x1;}
struct que{
int l=1, r=0; ll buc[N];
struct node{int val, pos; ll cnt; inline void build(int v, int p, ll c){val=v; pos=p; cnt=c;}}q[N];
void del(int line) {while (l<=r && q[l].pos<line) buc[q[l].val]=(buc[q[l].val]-q[l].cnt)%mod, ++l;}
int qmax() {return l<=r?q[l].val:0;}
int qcnt() {return (buc[q[l].val]+mod)%mod;}
void add(int val, int pos, ll cnt) {
while (l<=r && q[r].val<val) buc[q[r].val]=(buc[q[r].val]-q[r].cnt)%mod, --r;
q[++r].build(val, pos, cnt); buc[val]=(buc[val]+cnt)%mod;
}
void clear() {while (l<=r) buc[q[l].val]=(buc[q[l].val]-q[l].cnt)%mod, ++l; l=1; r=0;}
void show() {for (int i=l; i<=r; ++i) cout<<q[i].val<<','<<q[i].pos<<','<<q[i].cnt<<' '; cout<<endl;}
}qc[N], qr[N];
void solve() {
for (int i=1,a,b,c,d; i<=q; ++i) {
a=read(); b=read(); c=read(); d=read();
r[i].build(a, b, c, d);
}
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) left[i][j]=up[i][j]=0;
sort(r+1, r+q+1, cmp1);
for (int i=1; i<=m; ++i) for (int j=1; j<=n; ++j) dsu[i][j]=j, siz[i][j]=1, nxt[i][j]=j+1;
for (int i=1; i<=q; ++i) {
for (int j=r[i].y2; j>r[i].y1; --j) {
if (left[r[i].x1][j] && nxt[j][find(j, r[i].x1)]>r[i].x2) break;
int now=nxt[j][find(j, r[i].x1)];
while (now<=r[i].x2) {
if (!left[now][j]) {
left[now][j]=r[i].y1;
if (now>1 && left[now-1][j]) uni(j, now-1, now);
if (now<n && left[now+1][j]) uni(j, now, now+1);
}
now=nxt[j][find(j, now)];
}
}
}
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) if (!left[i][j]) left[i][j]=j;
// cout<<"left"<<endl;
// for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<left[i][j]<<' '; cout<<endl;}
sort(r+1, r+q+1, cmp2);
// cout<<"r: "; for (int i=1; i<=q; ++i) cout<<r[i].x1<<','<<r[i].y1<<','<<r[i].x2<<','<<r[i].y2<<' '; cout<<endl;
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) dsu[i][j]=j, siz[i][j]=1, nxt[i][j]=j+1;
for (int i=1; i<=q; ++i) {
for (int j=r[i].x2; j>r[i].x1; --j) {
// cout<<"i: "<<i<<' '<<j<<endl;
if (up[j][r[i].y1] && nxt[j][find(j, r[i].y1)]>r[i].y2) break;
// cout<<"ij: "<<i<<' '<<j<<endl;
int now=nxt[j][find(j, r[i].y1)];
while (now<=r[i].y2) {
if (!up[j][now]) {
up[j][now]=r[i].x1;
if (now>1 && up[j][now-1]) uni(j, now-1, now);
if (now<m && up[j][now+1]) uni(j, now, now+1);
}
now=nxt[j][find(j, now)];
}
}
}
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) if (!up[i][j]) up[i][j]=i;
// cout<<"up"<<endl;
// for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<up[i][j]<<' '; cout<<endl;}
int ans1=0; ll ans2=0;
for (int i=1; i<=n; ++i) {
for (int j=1; j<=m; ++j) {
// cout<<"ij: "<<i<<' '<<j<<endl;
// cout<<"del: "<<left[i][j]<<endl;
qr[i-1].del(left[i][j]);
qc[j-1].del(up[i][j]);
int maxn=max(qr[i-1].qmax(), qc[j-1].qmax());
ll cnt=0;
if (maxn) {
if (qr[i-1].qmax()==maxn) md(cnt, qr[i-1].qcnt()); //, cout<<"qrcnt: "<<qr[i-1].qcnt()<<endl;
if (qc[j-1].qmax()==maxn) md(cnt, qc[j-1].qcnt()); //, cout<<"qccnt: "<<qc[j-1].qcnt()<<endl;
// if (i==3 && j==4) qr[i-1].show();
f[i][j]=maxn+1; g[i][j]=cnt;
}
else f[i][j]=1, g[i][j]=1;
// printf("f[%d][%d]=%d, g[%d][%d]=%lld\n", i, j, f[i][j], i, j, g[i][j]);
// cout<<"max: "<<maxn<<' '<<cnt<<endl;
ans1=max(ans1, f[i][j]);
if (j>1) qr[i-1].add(f[i-1][j-1], j-1, g[i-1][j-1]);
}
for (int j=1; j<=m; ++j) qc[j].add(f[i][j], i, g[i][j]);
}
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) if (f[i][j]==ans1) md(ans2, g[i][j]);
printf("%d %lld\n", ans1, ans2);
for (int i=0; i<=n; ++i) qr[i].clear();
for (int i=0; i<=m; ++i) qc[i].clear();
}
}
signed main()
{
freopen("roche.in", "r", stdin);
freopen("roche.out", "w", stdout);
int T=read();
for (int i=1; i<=T; ++i) {
n=read(); m=read(); q=read();
// force::solve();
task::solve();
}
return 0;
}