题解 矩阵

传送门
[Ynoi2009] rprmq1

为了做这题去学了线段树历史最值和猫树分治
然后就没时间做这题了

发现只有一个前缀可以直接线段树历史最值
那么猫树的思想就是维护前后缀然后合并
恰好这个信息是可以 \(O(1)\) 合并的
那么对时间轴做线段树分治
将修改下放到 \(\log\) 个区间
按猫树的方式将查询放到 lca
在每个节点正反各做一次扫描线即可

  • 关于线段树历史最值的回滚操作:
    直接开栈记录被修改的节点固然可以,但有更简单的做法
    可以先做要撤销的操作的逆操作,然后全局加一个很大的 \(\Delta\),以后查值的时候减去 \(\Delta\)
    这样就相当于撤销了这几次操作对历史最值的影响

复杂度 \(O(n\log^2n+q\log n)\)在洛谷原题直接过了结果在学校 OJ 被卡了半天常

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 50010
#define fir first
#define sec second
#define pb push_back
#define ll long long
// #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;

namespace force{
	ll a[100][100];
	void solve() {
		for (int i=1,x1,x2,y1,y2,w; i<=m; ++i) {
			x1=read(); y1=read(); x2=read(); y2=read(); w=read();
			for (int j=x1; j<=x2; ++j)
				for (int k=y1; k<=y2; ++k)
					a[j][k]+=w;
		}
		for (int i=1,x1,x2,y1,y2,w; i<=q; ++i) {
			x1=read(); y1=read(); x2=read(); y2=read();
			ll ans=0;
			for (int j=x1; j<=x2; ++j)
				for (int k=y1; k<=y2; ++k)
					ans=max(ans, a[j][k]);
			printf("%lld\n", ans);
		}
	}
}

// namespace task1{
// 	int len, bel[120], ls[120], rs[120];
// 	struct blk{
// 		ll a[120], mx[120], tag[120];
// 		void rebuild(int id) {
// 			mx[id]=0;
// 			for (int i=ls[id]; i<=rs[id]; ++i) mx[id]=max(mx[id], a[i]);
// 		}
// 		void upd(int l, int r, int val) {
// 			int sid=bel[l], eid=bel[r];
// 			if (sid==eid) {
// 				for (int i=l; i<=r; ++i) a[i]+=val;
// 				rebuild(sid);
// 				return ;
// 			}
// 			for (int i=l; bel[i]==sid; ++i) a[i]+=val;
// 			for (int i=sid+1; i<eid; ++i) tag[i]+=val;
// 			for (int i=r; bel[i]==eid; --i) a[i]+=val;
// 			rebuild(sid); rebuild(eid);
// 		}
// 		ll query(int l, int r) {
// 			int sid=bel[l], eid=bel[r]; ll ans=0;
// 			if (sid==eid) {
// 				for (int i=l; i<=r; ++i) ans=max(ans, a[i]);
// 				return ans+=tag[sid];
// 			}
// 			for (int i=l; bel[i]==sid; ++i) ans=max(ans, a[i]+tag[sid]);
// 			for (int i=sid+1; i<eid; ++i) ans=max(ans, mx[i]+tag[i]);
// 			for (int i=r; bel[i]==eid; --i) ans=max(ans, a[i]+tag[eid]);
// 			return ans;
// 		}
// 	}
// 	void solve() {
// 		len=sqrt(n);
// 		memset(ls, 0x3f, sizeof(ls));
// 		for (int i=1; i<=n; ++i) bel[i]=(i-1)/len+1, ls[bel[i]]=min(ls[bel[i]], i), rs[bel[i]]=i;
// 		for (int i=1,x1,x2,y1,y2,w; i<=m; ++i) {
// 			x1=read(); y1=read(); x2=read(); y2=read(); w=read();
// 			for (int j=x1; j<=x2; ++j)
// 				for (int k=y1; k<=y2; ++k)
// 					a[j][k]+=w;
// 		}
// 		for (int i=1,x1,x2,y1,y2,w; i<=q; ++i) {
// 			x1=read(); y1=read(); x2=read(); y2=read();
// 			ll ans=0;
// 			for (int j=x1; j<=x2; ++j)
// 				for (int k=y1; k<=y2; ++k)
// 					ans=max(ans, a[j][k]);
// 			printf("%lld\n", ans);
// 		}
// 	}
// }

// ll mx[N*92], tag[N*92];
// int lson[N*92], rson[N*92], tot;

// namespace task2{
// 	struct tpl{int l, r, val;};
// 	vector<tpl> add[N];
// 	#define ls(p) lson[p]
// 	#define rs(p) rson[p]
// 	#define mx(p) mx[p]
// 	#define tag(p) tag[p]
// 	#define pushup(p) mx(p)=tag(p)+max(mx(ls(p)), mx(rs(p)))
// 	struct segment{
// 		int rot;
// 		// void spread(int p) {
// 		// 	if (!tag(p)) return ;
// 		// 	if (!ls(p)) ls(p)=++tot;
// 		// 	if (!rs(p)) rs(p)=++tot;
// 		// 	mx(ls(p))+=tag(p); tag(ls(p))+=tag(p);
// 		// 	mx(rs(p))+=tag(p); tag(rs(p))+=tag(p);
// 		// }
// 		void upd(int& p1, int p2, int tl, int tr, int ql, int qr, int val) {
// 			p1=++tot; ls(p1)=ls(p2); rs(p1)=rs(p2); tag(p1)=tag(p2);
// 			if (ql<=tl&&qr>=tr) {mx(p1)=mx(p2)+val; tag(p1)=tag(p2)+val; return ;}
// 			int mid=(tl+tr)>>1;
// 			if (ql<=mid) upd(ls(p1), ls(p2), tl, mid, ql, qr, val);
// 			if (qr>mid) upd(rs(p1), rs(p2), mid+1, tr, ql, qr, val);
// 			pushup(p1);
// 		}
// 		ll query(int p, int tl, int tr, int ql, int qr) {
// 			if (!p) return 0;
// 			if (ql<=tl&&qr>=tr) return mx(p);
// 			int mid=(tl+tr)>>1; ll ans=0;
// 			if (ql<=mid) ans=max(ans, query(ls(p), tl, mid, ql, qr));
// 			if (qr>mid) ans=max(ans, query(rs(p), mid+1, tr, ql, qr));
// 			return ans+tag(p);
// 		}
// 	}seg[N];
// 	void solve() {
// 		for (int i=1,x1,x2,y1,y2,w; i<=m; ++i) {
// 			x1=read(); y1=read(); x2=read(); y2=read(); w=read();
// 			add[x1].pb({y1, y2, w});
// 			add[x2+1].pb({y1, y2, -w});
// 		}
// 		for (int i=1; i<=n; ++i) {
// 			seg[i].rot=seg[i-1].rot;
// 			for (auto it:add[i]) seg[i].upd(seg[i].rot, seg[i].rot, 1, n, it.l, it.r, it.val);
// 		}
// 		for (int i=1,x1,x2,y1,y2,w; i<=q; ++i) {
// 			x1=read(); y1=read(); x2=read(); y2=read();
// 			ll ans=0;
// 			for (int j=x1; j<=x2; ++j)
// 				ans=max(ans, seg[j].query(seg[j].rot, 1, n, y1, y2));
// 			printf("%lld\n", ans);
// 		}
// 	}
// }

// namespace task3{
// 	ll ans[N], val[N];
// 	int bel[N], ls[N], rs[N], lsd[N], rsd[N], len, siz;
// 	struct tpl{int l, r, val;};
// 	vector<tpl> addx[N], addy[N], que[N];
// 	#define ls(p) lson[p]
// 	#define rs(p) rson[p]
// 	#define mx(p) mx[p]
// 	#define tag(p) tag[p]
// 	#define pushup(p) mx(p)=tag(p)+max(mx(ls(p)), mx(rs(p)))
// 	struct segment{
// 		int rot;
// 		void upd(int& p1, int p2, int tl, int tr, int ql, int qr, int val) {
// 			p1=++tot; ls(p1)=ls(p2); rs(p1)=rs(p2); tag(p1)=tag(p2);
// 			if (ql<=tl&&qr>=tr) {mx(p1)=mx(p2)+val; tag(p1)=tag(p2)+val; return ;}
// 			int mid=(tl+tr)>>1;
// 			if (ql<=mid) upd(ls(p1), ls(p2), tl, mid, ql, qr, val);
// 			if (qr>mid) upd(rs(p1), rs(p2), mid+1, tr, ql, qr, val);
// 			pushup(p1);
// 		}
// 		ll query(int p, int tl, int tr, int ql, int qr) {
// 			if (!p) return 0;
// 			if (ql<=tl&&qr>=tr) return mx(p);
// 			int mid=(tl+tr)>>1; ll ans=0;
// 			if (ql<=mid) ans=max(ans, query(ls(p), tl, mid, ql, qr));
// 			if (qr>mid) ans=max(ans, query(rs(p), mid+1, tr, ql, qr));
// 			return ans+tag(p);
// 		}
// 	}segx[N], segy[N];
// 	struct blk{
// 		ll a[N], mx[N], tag[N];
// 		void rebuild(int id) {
// 			mx[id]=0;
// 			for (int i=lsd[id]; i<=rsd[id]; ++i) mx[id]=max(mx[id], a[i]);
// 		}
// 		void upd(int l, int r, int val) {
// 			int sid=bel[l], eid=bel[r];
// 			if (sid==eid) {
// 				for (int i=l; i<=r; ++i) a[i]+=val;
// 				rebuild(sid);
// 				return ;
// 			}
// 			for (int i=l; bel[i]==sid; ++i) a[i]+=val;
// 			for (int i=sid+1; i<eid; ++i) tag[i]+=val;
// 			for (int i=r; bel[i]==eid; --i) a[i]+=val;
// 			rebuild(sid); rebuild(eid);
// 		}
// 		// ll query(int l, int r) {
// 		// 	int sid=bel[l], eid=bel[r]; ll ans=0;
// 		// 	if (sid==eid) {
// 		// 		for (int i=l; i<=r; ++i) ans=max(ans, a[i]);
// 		// 		return ans+=tag[sid];
// 		// 	}
// 		// 	for (int i=l; bel[i]==sid; ++i) ans=max(ans, a[i]+tag[sid]);
// 		// 	for (int i=sid+1; i<eid; ++i) ans=max(ans, mx[i]+tag[i]);
// 		// 	for (int i=r; bel[i]==eid; --i) ans=max(ans, a[i]+tag[eid]);
// 		// 	return ans;
// 		// }
// 		ll query(int id) {return mx[id]+tag[id];}
// 	}bk;
// 	void solve() {
// 		len=50;
// 		memset(lsd, 0x3f, sizeof(lsd));
// 		for (int i=1; i<=n; ++i) bel[i]=(i-1)/len+1, lsd[bel[i]]=min(lsd[bel[i]], i), rsd[bel[i]]=i;
// 		siz=bel[n];
// 		for (int i=1,x1,x2,y1,y2,w; i<=m; ++i) {
// 			x1=read(); y1=read(); x2=read(); y2=read(); w=read();
// 			addx[x1].pb({y1, y2, w});
// 			addx[x2+1].pb({y1, y2, -w});
// 			addy[y1].pb({x1, x2, w});
// 			addy[y2+1].pb({x1, x2, -w});
// 		}
// 		for (int i=1; i<=n; ++i) {
// 			segx[i].rot=segx[i-1].rot;
// 			for (auto it:addx[i]) segx[i].upd(segx[i].rot, segx[i].rot, 1, n, it.l, it.r, it.val);
// 		}
// 		for (int i=1; i<=n; ++i) {
// 			segy[i].rot=segy[i-1].rot;
// 			for (auto it:addy[i]) segy[i].upd(segy[i].rot, segy[i].rot, 1, n, it.l, it.r, it.val);
// 		}
// 		for (int i=1,x1,x2,y1,y2,w; i<=q; ++i) {
// 			x1=read(); y1=read(); x2=read(); y2=read();
// 			que[x2].pb({y1, y2, i});
// 		}
// 		for (int i=1; i<=n; ++i) {
// 			// for (int j=1; j<=siz; ++j) val[j]=max(val[j], segx[i].query(segx[i].rot, 1, n, lsd[j], rsd[j]));
// 			// for (auto it:addx[i]) segx[i].upd(segx[i].rot, segx[i].rot, 1, n, it.l, it.r, it.val);
// 			for (auto it:addx[i]) bk.upd(it.l, it.r, it.val);
// 			for (int j=1; j<=siz; ++j) val[j]=max(val[j], bk.query(j));
// 			// for (int j=1; j<=siz; ++j) val[j]=bk.query(j);
// 			for (auto it:que[i]) {
// 				int l=it.l, r=it.r;
// 				int sid=bel[l], eid=bel[r];
// 				ll ans=0;
// 				if (sid==eid) {for (int j=l; j<=r; ++j) ans=max(ans, segy[j].query(segy[j].rot, 1, n, 1, i));}
// 				else {
// 					for (int j=l; bel[j]==sid; ++j) ans=max(ans, segy[j].query(segy[j].rot, 1, n, 1, i));
// 					for (int j=sid+1; j<eid; ++j) ans=max(ans, val[j]);
// 					for (int j=r; bel[j]==eid; --j) ans=max(ans, segy[j].query(segy[j].rot, 1, n, 1, i));
// 				}
// 				task3::ans[it.val]=ans;
// 			}
// 		}
// 		for (int i=1; i<=q; ++i) printf("%lld\n", ans[i]);
// 	}
// }

namespace task{
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#undef pushup
	struct tpl{int l, r, val;};
	struct op{int l, r; tpl val;};
	inline tpl operator - (tpl a) {return {a.l, a.r, -a.val};}
	inline bool operator < (tpl a, tpl b) {return a.val<b.val;}
	struct segment{
		int tl[N<<2], tr[N<<2];
		ll mx[N<<2], his_mx[N<<2], add[N<<2], his_add[N<<2];
		void pushup(int p) {
			mx[p]=max(mx[p<<1], mx[p<<1|1]);
			his_mx[p]=max(his_mx[p<<1], his_mx[p<<1|1]);
		}
		void spread_add(int p, ll& val, ll& his_val) {
			his_mx[p]=max(his_mx[p], mx[p]+his_val);
			his_add[p]=max(his_add[p], add[p]+his_val);
			mx[p]+=val; add[p]+=val;
		}
		void spread(int p) {
			if (!add[p]&&!his_add[p]) return ;
			spread_add(p<<1, add[p], his_add[p]);
			spread_add(p<<1|1, add[p], his_add[p]);
			add[p]=his_add[p]=0;
		}
		void build(int p, int l, int r) {
			tl(p)=l; tr(p)=r;
			if (l==r) return ;
			int mid=(l+r)>>1;
			build(p<<1, l, mid);
			build(p<<1|1, mid+1, r);
		}
		void upd(int p, int l, int r, ll val) {
			if (l<=tl(p)&&r>=tr(p)) {
				his_mx[p]=max(his_mx[p], mx[p]+=val);
				his_add[p]=max(his_add[p], add[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);
		}
		ll query(int p, int l, int r) {
			if (l<=tl(p)&&r>=tr(p)) return his_mx[p];
			spread(p);
			int mid=(tl(p)+tr(p))>>1; ll ans=0;
			if (l<=mid) ans=max(ans, query(p<<1, l, r));
			if (r>mid) ans=max(ans, query(p<<1|1, l, r));
			return ans;
		}
		ll qmax(int p, int l, int r) {
			if (l<=tl(p)&&r>=tr(p)) return mx[p];
			spread(p);
			int mid=(tl(p)+tr(p))>>1; ll ans=0;
			if (l<=mid) ans=max(ans, qmax(p<<1, l, r));
			if (r>mid) ans=max(ans, qmax(p<<1|1, l, r));
			return ans;
		}
	}seg;
	ll ans[500010], dlt;
	int tl[N<<2], tr[N<<2];
	vector<op> upd[N<<2], que[N<<2];
	vector<tpl> _buc[19][N], _qry[19][N], all[N<<2];
	void build(int p, int l, int r) {
		// cout<<"build: "<<p<<' '<<l<<' '<<r<<endl;
		tl(p)=l; tr(p)=r;
		if (l==r) return ;
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
	}
	void modify(int p, int l, int r, tpl val) {
		if (l<=tl(p)&&r>=tr(p)) {all[p].pb(val); return ;}
		upd[p].pb({l, r, val});
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) modify(p<<1, l, r, val);
		if (r>mid) modify(p<<1|1, l, r, val);
	}
	void query(int p, int l, int r, tpl val) {
		if (tl(p)==tr(p)) {que[p].pb({l, r, val}); return ;}
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid&&r>mid) {que[p].pb({l, r, val}); return ;}
		if (r<=mid) query(p<<1, l, r, val);
		else query(p<<1|1, l, r, val);
	}
	void solve(int p, int dep) {
		// cout<<"solve: "<<p<<endl;
		ll sum1=0, sum2=0;
		int l=tl(p), r=tr(p), mid=(l+r)>>1;
		// cout<<"lr: "<<l<<' '<<r<<' '<<mid<<endl;
		vector<tpl>* qry=_qry[dep];
		vector<tpl>* buc=_buc[dep];
		for (int i=l; i<=r; ++i) buc[i].clear(), qry[i].clear();
		for (auto& it:all[p]) seg.upd(1, it.l, it.r, it.val), sum1+=it.val;
		for (auto& it:que[p]) qry[it.l].pb(it.val), qry[it.r].pb(it.val);
		if (!que[p].size()) goto jump;

		for (auto& it:upd[p]) {
			sum2+=it.val.val;
			if (it.l<=mid&&it.r>mid) seg.upd(1, it.val.l, it.val.r, it.val.val); //, cout<<"pre_add: "<<it.val.val<<endl;
			if (it.r>mid) {
				buc[max(it.l, l)].pb(it.val);
				buc[min(it.r, r)+1].pb(-it.val);
			}
		}
		for (int i=l; i<=r; ++i) sort(buc[i].begin(), buc[i].end());
		// cout<<"---buc---"<<endl; for (int i=l; i<=r; ++i) {cout<<i<<": "; for (auto it:buc[i]) cout<<"("<<it.l<<','<<it.r<<','<<it.val<<") "; cout<<endl;}
		// cout<<"---qry---"<<endl; for (int i=l; i<=r; ++i) {cout<<i<<": "; for (auto it:qry[i]) cout<<"("<<it.l<<','<<it.r<<','<<it.val<<") "; cout<<endl;}
		for (int i=mid+1; i<=r; ++i) {
			for (auto& it:buc[i]) seg.upd(1, it.l, it.r, it.val); //, cout<<"scan_add: "<<it.val<<endl;
			for (auto& it:qry[i]) ans[it.val]=max(ans[it.val], seg.query(1, it.l, it.r)-dlt);
		}
		for (int i=r; i>=l; --i) for (auto& it:buc[i]) seg.upd(1, it.l, it.r, -it.val);
		// cout<<"before reset: "<<seg.qmax(1, 1, n)<<endl;
		seg.upd(1, 1, n, sum2); dlt+=sum2;
		// cout<<"after reset: "<<seg.qmax(1, 1, n)<<endl;

		for (int i=l; i<=r; ++i) buc[i].clear();
		for (auto& it:upd[p]) {
			if (it.l<=mid&&it.r>mid) seg.upd(1, it.val.l, it.val.r, it.val.val);
			if (it.l<=mid) {
				buc[min(it.r, r)].pb(it.val);
				buc[max(it.l, l)-1].pb(-it.val);
			}
		}
		for (int i=l; i<=r; ++i) sort(buc[i].begin(), buc[i].end());
		// cout<<"---buc---"<<endl; for (int i=l; i<=r; ++i) {cout<<i<<": "; for (auto it:buc[i]) cout<<"("<<it.l<<','<<it.r<<','<<it.val<<") "; cout<<endl;}
		// cout<<"---qry---"<<endl; for (int i=l; i<=r; ++i) {cout<<i<<": "; for (auto it:qry[i]) cout<<"("<<it.l<<','<<it.r<<','<<it.val<<") "; cout<<endl;}
		for (int i=mid; i>=l; --i) {
			// cout<<"pre: "<<seg.qmax(1, 1, n)<<endl;
			for (auto& it:buc[i]) seg.upd(1, it.l, it.r, it.val); //, cout<<"add: "<<it.l<<' '<<it.r<<' '<<it.val<<endl;
			for (auto& it:qry[i]) ans[it.val]=max(ans[it.val], seg.query(1, it.l, it.r)-dlt); //, cout<<seg.query(1, it.l, it.r)-dlt<<endl;
		}
		for (int i=l; i<=r; ++i) for (auto& it:buc[i]) seg.upd(1, it.l, it.r, -it.val);
		seg.upd(1, 1, n, sum2); dlt+=sum2;
		jump: ;
		if (tl(p)!=tr(p)) solve(p<<1, dep+1), solve(p<<1|1, dep+1);
		for (auto& it:all[p]) seg.upd(1, it.l, it.r, -it.val);
		seg.upd(1, 1, n, sum1); dlt+=sum1;
	}
	void solve() {
		// cout<<double(sizeof(ans)+sizeof(tl)*2+sizeof(upd)*2+sizeof(_buc)*2+sizeof(all))/1000/1000<<endl; exit(0);
		build(1, 1, n); seg.build(1, 1, n);
		for (int i=1,x1,x2,y1,y2,w; i<=m; ++i) {
			x1=read(); y1=read(); x2=read(); y2=read(); w=read();
			modify(1, x1, x2, {y1, y2, w});
		}
		for (int i=1,x1,x2,y1,y2; i<=q; ++i) {
			x1=read(); y1=read(); x2=read(); y2=read();
			query(1, x1, x2, {y1, y2, i});
		}
		solve(1, 1);
		for (int i=1; i<=q; ++i) printf("%lld\n", ans[i]);
	}
}

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

	n=read(); m=read(); q=read();
	// cout<<double(sizeof(task3::bel)*30+sizeof(lson)*6)/1000/1000<<endl; exit(0);
	// force::solve();
	// task3::solve();
	// if (n<=100 || q<=10) task2::solve();
	// else task3::solve();
	task::solve();

	return 0;
}
posted @ 2022-04-03 21:26  Administrator-09  阅读(1)  评论(0编辑  收藏  举报