题解 铺地毯

传送门

尝试扫描线,没调出来
考完才发现我试图用线段树的pushup完成对值域的离散化
这样极为难写
扫描线上的所有点会将线分成几个形如 \([y_i, y_{i+1}]\) 的区间
令一个 \(c_i\) 为区间 \([y_i, y_{i+1}]\) 被覆盖的次数,维护这个东西即可

但是还有一个 \(O(n)\) 做法
尝试求出 \(n-1\) 个矩形的面积交的并
发现 \(n-1\) 个矩形的面积交可以用一个前缀交和一个后缀交实现
于是 \(n-1\) 个矩形的面积交的重叠部分就是所有矩形的交,减去即可
复杂度 \(O(n)\)

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 600010
#define ll long long
#define fir first
#define sec second
#define make make_pair
#define pb push_back
//#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, p, q;
int a[N], b[N], c[N], d[N];

namespace force{
	int cnt[100][100];
	void solve() {
		int ans=0;
		memset(cnt, 0, sizeof(cnt));
		for (int i=1; i<=n; ++i) {
			int a=read(), b=read(), c=read()-1, d=read()-1;
			for (int j=a; j<=c; ++j) for (int k=b; k<=d; ++k) ++cnt[j][k];
		}
		for (int i=0; i<100; ++i) for (int j=0; j<100; ++j) if (cnt[i][j]>=n-1) ++ans;
		printf("%d\n", ans);
	}
}

namespace task1{
	#undef unix
	int unix[N], usizx, uniy[N], usizy;
	vector<pair<int, int>> add[N], del[N];
	int tl[N<<2], tr[N<<2], fir[N<<2], fcnt[N<<2], sec[N<<2], scnt[N<<2], tag[N<<2];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define dat(p) dat[p]
	void pushup(int p) {
		int max1=0, max2=0;
		max1=max(fir[p<<1], fir[p<<1|1]);
		if (fir[p<<1]!=max1) max2=max(max2, fir[p<<1]);
		if (fir[p<<1|1]!=max1) max2=max(max2, fir[p<<1|1]);
		max2=max(max2, max(sec[p<<1], sec[p<<1|1]));
		fir[p]=max1; sec[p]=max2; fcnt[p]=scnt[p]=0;
		if (fir[p<<1]==max1) fcnt[p]+=fcnt[p<<1];
		if (fir[p<<1|1]==max1) fcnt[p]+=fcnt[p<<1|1];
		if (fir[p<<1]==max2) scnt[p]+=fcnt[p<<1];
		if (fir[p<<1|1]==max2) scnt[p]+=fcnt[p<<1|1];
		if (sec[p<<1]==max2) scnt[p]+=scnt[p<<1];
		if (sec[p<<1|1]==max2) scnt[p]+=scnt[p<<1|1];
	}
	void spread(int p) {
		if (!tag[p]) return ;
		fir[p<<1]+=tag[p]; tag[p<<1]+=tag[p]; if (sec[p<<1]) sec[p<<1]+=tag[p];
		fir[p<<1|1]+=tag[p]; tag[p<<1|1]+=tag[p]; if (sec[p<<1|1]) sec[p<<1|1]+=tag[p];
		tag[p]=0;
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r; fir[p]=fcnt[p]=sec[p]=scnt[p]=tag[p]=0;
		if (l==r) {fcnt[p]=scnt[p]=1; return ;}
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
		pushup(p);
	}
	void upd(int p, int l, int r, int val) {
		if (l<=tl(p) && r>=tr(p)) {
			cout<<"at: "<<p<<' '<<tl(p)<<' '<<tr(p)<<' '<<fir[p]<<' '<<fcnt[p]<<endl;
			fir[p]+=val; tag[p]+=val;
			if (sec[p]) sec[p]+=val;
			return ;
		}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) upd(p<<1, l, r, val);
		if (r>mid) upd(p<<1|1, l, r, val);
		pushup(p);
	}
	void solve() {
		ll ans=0;
		for (int i=1; i<=n; ++i) {
			a[i]=read(); b[i]=read(); c[i]=read()-1; d[i]=read()-1;
			unix[++usizx]=a[i]; unix[++usizx]=c[i];
			uniy[++usizy]=b[i]; uniy[++usizy]=d[i];
		}
		// sort(unix+1, unix+usizx+1); sort(uniy+1, uniy+usizy+1);
		// usizx=unique(unix+1, unix+usizx+1)-unix-1; usizy=unique(uniy+1, uniy+usizy+1)-uniy-1;
		build(1, 1, q);
		for (int i=1; i<=max(p, q); ++i) add[i].clear(), del[i].clear();
		for (int i=1; i<=n; ++i) {
			// add[lower_bound(unix+1, unix+usizx+1, a[i])-unix].pb(make(lower_bound(uniy+1, uniy+usizy+1, b[i])-uniy, lower_bound(uniy+1, uniy+usizy+1, d[i])-uniy));
			// cout<<"add: "<<lower_bound(unix+1, unix+usizx+1, a[i])-unix<<endl;
			// del[lower_bound(unix+1, unix+usizx+1, c[i])-unix].pb(make(lower_bound(uniy+1, uniy+usizy+1, b[i])-uniy, lower_bound(uniy+1, uniy+usizy+1, d[i])-uniy));
			add[a[i]].pb(make(b[i], d[i]));
			del[c[i]].pb(make(b[i], d[i]));
		}
		for (int i=1; i<=10; ++i) {
			cout<<"i: "<<i<<endl;
			for (auto it:add[i]) upd(1, it.fir, it.sec, 1), cout<<"upd: "<<it.fir<<' '<<it.sec<<endl;
			cout<<"fir: "<<fir[1]<<' '<<fcnt[1]<<endl;
			cout<<"sec: "<<sec[1]<<' '<<scnt[1]<<endl;
			if (fir[1] && fir[1]>=n-1) ans+=fcnt[1];
			if (sec[1] && sec[1]>=n-1) ans+=scnt[1];
			for (auto it:del[i]) upd(1, it.fir, it.sec, -1);
		}
		printf("%lld\n", ans);
	}
}

namespace task2{
	#undef unix
	int unix[N], usizx, uniy[N], usizy;
	vector<pair<int, int>> add[N], del[N];
	int tl[N<<2], tr[N<<2], fir[N<<2], fcnt[N<<2], sec[N<<2], scnt[N<<2], tag[N<<2];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define dat(p) dat[p]
	void pushup(int p) {
		int max1=0, max2=0;
		max1=max(fir[p<<1], fir[p<<1|1]);
		if (fir[p<<1]!=max1) max2=max(max2, fir[p<<1]);
		if (fir[p<<1|1]!=max1) max2=max(max2, fir[p<<1|1]);
		max2=max(max2, max(sec[p<<1], sec[p<<1|1]));
		fir[p]=max1; sec[p]=max2; fcnt[p]=scnt[p]=0;
		if (fir[p<<1]==max1) fcnt[p]+=fcnt[p<<1];
		if (fir[p<<1|1]==max1) fcnt[p]+=fcnt[p<<1|1];
		if (fir[p<<1]==max2) scnt[p]+=fcnt[p<<1];
		if (fir[p<<1|1]==max2) scnt[p]+=fcnt[p<<1|1];
		if (sec[p<<1]==max2) scnt[p]+=scnt[p<<1];
		if (sec[p<<1|1]==max2) scnt[p]+=scnt[p<<1|1];
	}
	void spread(int p) {
		if (!tag[p]) return ;
		fir[p<<1]+=tag[p]; tag[p<<1]+=tag[p]; if (sec[p<<1]) sec[p<<1]+=tag[p];
		fir[p<<1|1]+=tag[p]; tag[p<<1|1]+=tag[p]; if (sec[p<<1|1]) sec[p<<1|1]+=tag[p];
		tag[p]=0;
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r; fir[p]=fcnt[p]=sec[p]=scnt[p]=tag[p]=0;
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
		pushup(p);
	}
	void upd(int p, int l, int r, int val) {
		if (l<=tl(p) && r>=tr(p)) {
			cout<<"at: "<<p<<' '<<tl(p)<<' '<<tr(p)<<' '<<fir[p]<<' '<<fcnt[p]<<endl;
			fir[p]+=val; tag[p]+=val;
			if (sec[p]) sec[p]+=val;
			return ;
		}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) upd(p<<1, l, r, val);
		if (r>mid) upd(p<<1|1, l, r, val);
		pushup(p);
	}
	void solve() {
		ll ans=0;
		for (int i=1; i<=n; ++i) {
			a[i]=read(); b[i]=read(); c[i]=read()-1; d[i]=read()-1;
			unix[++usizx]=a[i]; unix[++usizx]=c[i];
			uniy[++usizy]=b[i]; uniy[++usizy]=d[i];
		}
		// sort(unix+1, unix+usizx+1); sort(uniy+1, uniy+usizy+1);
		// usizx=unique(unix+1, unix+usizx+1)-unix-1; usizy=unique(uniy+1, uniy+usizy+1)-uniy-1;
		build(1, 1, usizy);
		for (int i=1; i<=usizx; ++i) add[i].clear(), del[i].clear();
		for (int i=1; i<=n; ++i) {
			// add[lower_bound(unix+1, unix+usizx+1, a[i])-unix].pb(make(lower_bound(uniy+1, uniy+usizy+1, b[i])-uniy, lower_bound(uniy+1, uniy+usizy+1, d[i])-uniy));
			// cout<<"add: "<<lower_bound(unix+1, unix+usizx+1, a[i])-unix<<endl;
			// del[lower_bound(unix+1, unix+usizx+1, c[i])-unix].pb(make(lower_bound(uniy+1, uniy+usizy+1, b[i])-uniy, lower_bound(uniy+1, uniy+usizy+1, d[i])-uniy));
			
		}
		for (int i=1; i<=usizx; ++i) {
			cout<<"i: "<<i<<endl;
			for (auto it:add[i]) upd(1, it.fir, it.sec, 1), cout<<"upd: "<<it.fir<<' '<<it.sec<<endl;
			cout<<"fir: "<<fir[1]<<' '<<fcnt[1]<<endl;
			cout<<"sec: "<<sec[1]<<' '<<scnt[1]<<endl;
			if (fir[1]>=n-1) ans+=fcnt[1];
			if (sec[1]>=n-1) ans+=scnt[1];
			for (auto it:del[i]) upd(1, it.fir, it.sec, -1);
		}
		printf("%lld\n", ans);
	}
}

namespace task{
	ll ans;
	struct rec{
		int a, b, c, d;
		rec(){}
		rec(int w, int x, int y, int z) {a=w; b=x; c=y; d=z;}
		inline void build() {a=read(); b=read(); c=read()-1; d=read()-1;}
		inline void build(int w, int x, int y, int z) {a=w; b=x; c=y; d=z;}
		inline ll s() {
			if (a>c || b>d) return 0;
			else return 1ll*(c-a+1)*(d-b+1);
		}
	}r[N], cap, sum[N], suf[N];
	inline rec operator & (rec a, rec b) {return rec(max(a.a, b.a), max(a.b, b.b), min(a.c, b.c), min(a.d, b.d));}
	void solve() {
		for (int i=1; i<=n; ++i) r[i].build();
		if (n==1) {printf("%lld\n", r[1].s()); return ;}
		cap=r[1]; ans=0;
		for (int i=2; i<=n; ++i) cap=cap&r[i];
		sum[1]=r[1]; suf[n]=r[n];
		for (int i=2; i<=n; ++i) sum[i]=sum[i-1]&r[i];
		for (int i=n-1; i; --i) suf[i]=suf[i+1]&r[i];
		// cout<<"sum: "; for (int i=1; i<=n; ++i) cout<<sum[i].s()<<' '; cout<<endl;
		// cout<<"suf: "; for (int i=1; i<=n; ++i) cout<<suf[i].s()<<' '; cout<<endl;
		ans+=suf[2].s()-cap.s();
		ans+=sum[n-1].s()-cap.s();
		for (int i=2; i<n; ++i) ans+=(sum[i-1]&suf[i+1]).s()-cap.s(); //, cout<<"add: "<<(sum[i-1]&suf[i+1]).s()<<endl;
		ans+=cap.s();
		printf("%lld\n", ans);
	}
}

signed main()
{
	freopen("carpet.in", "r", stdin);
	freopen("carpet.out", "w", stdout);

	int T=read();
	while (T--) {
		p=read(); q=read(); n=read();
		// force::solve();
		// task1::solve();
		task::solve();
	}
	
	return 0;
}
posted @ 2021-11-07 16:51  Administrator-09  阅读(0)  评论(0编辑  收藏  举报