题解 军队

传送门

  • 关于线段树上带修维护 \(\leqslant k\) 的元素个数(需保证任意时刻每个元素都是非负整数):
    可以在每个节点记录前 \(k\) 小的元素大小和数量,可以归并合并
    查询的时候就按顺序枚举,若这个数 \(\leqslant k\) 就统计到答案里

于是可以扫描线求出每一行雌/雄性各有多少个
然后怎么快速回答每个询问呢?
\(b_i=min(a_i, m-a_i)\),则随着 \(b_i\)\(x\) 大小关系的不同是一个分段函数

  • 对一个多次询问,每次的分界点与输入相关但两部分的斜率不变,要多次求值的问题:
    可以每次根据斜率二分出分界点,对原来两部分分别用前缀和求值
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#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, m, c, k, q;

namespace force{
	int mp[3010][3010], a[N], b[N];
	ll rem[3010][3010];
	pair<ll, ll> tem[N];
	void solve() {
		memset(rem, -1, sizeof(rem));
		for (int i=1,x1,y1,x2,y2; i<=c; ++i) {
			x1=read(); y1=read(); x2=read(); y2=read();
			++mp[x1][y1]; --mp[x1][y2+1]; --mp[x2+1][y1]; ++mp[x2+1][y2+1];
		}
		for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) mp[i][j]=mp[i][j]+mp[i-1][j]+mp[i][j-1]-mp[i-1][j-1]; //, cout<<"mp: "<<i<<' '<<j<<' '<<mp[i][j]<<endl;
		for (int i=1; i<=n; ++i)
			for (int j=1; j<=m; ++j)
				if (mp[i][j]<k) ++a[i];
				else ++b[i];
		// for (int i=1; i<=n; ++i) cout<<"ab: "<<a[i]<<' '<<b[i]<<endl;
		for (int i=1; i<=n; ++i) tem[i]=make(min(a[i], b[i]), max(a[i], b[i])-min(a[i], b[i]));
		sort(tem+1, tem+n+1); reverse(tem+1, tem+n+1);
		// for (int i=1; i<=n; ++i) cout<<tem[i].fir<<' '<<tem[i].sec<<endl;
		for (int i=1,x,y; i<=q; ++i) {
			x=read(); y=read();
			if (~rem[x][y]) printf("%lld\n", rem[x][y]);
			else {
				ll ans=0;
				for (int j=1; j<=x; ++j) {
					if (y<=tem[j].fir*2) ans+=(y/2)*(y-y/2);
					else ans+=tem[j].fir*(y-tem[j].fir);
				}
				// cout<<"ans: "<<ans<<endl;
				printf("%lld\n", rem[x][y]=ans);
			}
		}
		exit(0);
	}
}

namespace task{
	int x1[N], y1[N], x2[N], y2[N], len[N], a[N], b[N];
	int tl[N<<2], tr[N<<2], tot[N<<2], uni[N<<1], tag[N<<2], usiz;
	ll sum[N], sum2[N];
	pair<int, int> dat[N<<2][11];
	vector<pair<int, int>> add[N], del[N];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	#define tot(p) tot[p]
	#define tag(p) tag[p]
	#define dat(p, k) dat[p][k]
	void spread(int p) {
		if (!tag(p)) return ;
		tag(p<<1)+=tag(p); tag(p<<1|1)+=tag(p);
		for (int i=1; i<=tot(p<<1); ++i) dat(p<<1, i).fir+=tag(p);
		for (int i=1; i<=tot(p<<1|1); ++i) dat(p<<1|1, i).fir+=tag(p);
		tag(p)=0;
	}
	void pushup(int p) {
		int pos1=1, pos2=1; tot(p)=0;
		while ((pos1<=tot(p<<1)||pos2<=tot(p<<1|1)) && tot(p)<=k) {
			if (pos1>tot(p<<1)) dat(p, ++tot(p))=dat(p<<1|1, pos2++);
			else if (pos2>tot(p<<1|1)) dat(p, ++tot(p))=dat(p<<1, pos1++);
			else if (dat(p<<1, pos1).fir==dat(p<<1|1, pos2).fir) dat(p, ++tot(p))=make(dat(p<<1, pos1).fir, dat(p<<1, pos1).sec+dat(p<<1|1, pos2).sec), ++pos1, ++pos2;
			else if (dat(p<<1, pos1).fir<dat(p<<1|1, pos2).fir) dat(p, ++tot(p))=dat(p<<1, pos1++);
			else if (dat(p<<1, pos1).fir>dat(p<<1|1, pos2).fir) dat(p, ++tot(p))=dat(p<<1|1, pos2++);
			else puts("error");
		}
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r;
		if (l==r) {dat(p, ++tot(p))=make(0, len[l]); 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)) {
			tag(p)+=val;
			for (int i=1; i<=tot(p); ++i) dat(p, i).fir+=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);
	}
	int query() {
		int ans=0;
		// cout<<"query: "<<tot(1)<<endl;
		// for (int i=1; i<=tot(1); ++i) cout<<dat(1, i).fir<<','<<dat(1, i).sec<<endl;
		for (int i=1; i<=tot(1)&&dat(1, i).fir<k; ++i) ans+=dat(1, i).sec;
		return ans;
	}
	void solve() {
		for (int i=1; i<=c; ++i) {
			x1[i]=read(); y1[i]=read(); x2[i]=read()+1; y2[i]=read()+1;
			uni[++usiz]=y1[i]; uni[++usiz]=y2[i];
			// cout<<"y: "<<y1[i]<<' '<<y2[i]<<endl;
		}
		uni[++usiz]=1; uni[++usiz]=m+1;
		sort(uni+1, uni+usiz+1);
		usiz=unique(uni+1, uni+usiz+1)-uni-1;
		for (int i=1; i<usiz; ++i) len[i]=uni[i+1]-uni[i];
		build(1, 1, usiz);
		// cout<<"usiz: "<<usiz<<endl;
		// cout<<tot(1)<<endl;
		// cout<<dat(1, 1).fir<<' '<<dat(1, 1).sec<<endl;
		// cout<<"uni: "; for (int i=1; i<=usiz; ++i) cout<<uni[i]<<' '; cout<<endl;
		for (int i=1; i<=c; ++i) {
			add[x1[i]].pb(make(lower_bound(uni+1, uni+usiz+1, y1[i])-uni, lower_bound(uni+1, uni+usiz+1, y2[i])-uni-1));
			del[x2[i]].pb(make(lower_bound(uni+1, uni+usiz+1, y1[i])-uni, lower_bound(uni+1, uni+usiz+1, y2[i])-uni-1));
		}
		for (int i=1; i<=n; ++i) {
			// cout<<"i: "<<i<<endl;
			for (auto it:add[i]) upd(1, it.fir, it.sec, 1); //, cout<<"upd: "<<it.fir<<' '<<it.sec<<endl;
			for (auto it:del[i]) upd(1, it.fir, it.sec, -1);
			a[i]=query(); b[i]=min(a[i], m-a[i]);
			// b[i]=m-a[i];
			// cout<<"ab: "<<i<<' '<<a[i]<<' '<<b[i]<<endl;
		}
		sort(b+1, b+n+1, [](int a, int b){return a>b;});
		for (int i=1; i<=n; ++i) sum[i]=sum[i-1]+b[i];
		for (int i=1; i<=n; ++i) sum2[i]=sum2[i-1]+1ll*b[i]*b[i];
		// cout<<"b: "; for (int i=1; i<=n; ++i) cout<<b[i]<<' '; cout<<endl;
		// return ;
		for (int i=1,x,y; i<=q; ++i) {
			x=read(); y=read();
			// cout<<"xy: "<<x<<' '<<y<<endl;
			int t=upper_bound(b+1, b+n+1, y/2, [](int a, int b){return a>b;})-b-1;
			// cout<<"t: "<<t<<endl;
			if (t>=x && b[t]>=y/2) printf("%lld\n", 1ll*x*(y/2)*(y-y/2)); //, cout<<"tem"<<endl;
			else {
				ll ans=1ll*t*(y/2)*(y-y/2);
				ans+=(sum[x]-sum[t])*y-(sum2[x]-sum2[t]);
				printf("%lld\n", ans);
			}
		}
		exit(0);
	}
}

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

	n=read(); m=read(); c=read(); k=read(); q=read();
	// force::solve();
	task::solve();

	return 0;
}
posted @ 2021-11-16 21:43  Administrator-09  阅读(5)  评论(0编辑  收藏  举报