【NOI P模拟赛】混凝土粉末(整体二分)

题面

在这里插入图片描述
样例输入

5 8
1 1 4 2
2 3 1
2 3 3
1 2 5 1
2 3 3
2 5 2
2 1 2
2 1 3

样例输出

1
0
4
0
1
0

样例解释
在这里插入图片描述
在这里插入图片描述

题解

这道题简单了不知多少倍。

我们可以把所有询问操作放到最后,计算出答案之后,再判断每个询问的答案是否超出原本限制,超过了就输出 0 。

把询问跟操作分开后,整体二分就行了。知道整体二分的基本都应该想到怎么做了吧:

所有操作按照原序(混凝土种类从小到大),所有询问按照 x x x 从小到大排。

递归到操作区间 [ l , r ] [l,r] [l,r] 、同时对应询问区间 [ l 2 , r 2 ] [l_2,r_2] [l2,r2] 时,定操作区间的中点为 m i d = ⌊ l + r 2 ⌋ {\rm mid} = \lfloor\frac{l+r}{2}\rfloor mid=2l+r 。我们把一个操作看成是两个二元组 (l,h)(r+1,-h) ,表示把 [ l , + ∞ ] [{\rm l},+\infty] [l,+] 的区域整体加 h h h,同时把 [ r , + ∞ ] [{\rm r},+\infty] [r,+] 的区域整体加 − h -h h

我们处理出操作区间 [ l , m i d ] [l,{\rm mid}] [l,mid] 内的所有二元组按照第一个元素从小到大排序后的序列 s t st st ,然后一边遍历询问区间 [ l 2 , r 2 ] [l_2,r_2] [l2,r2] ,一边用扫描线扫描序列 s t st st ,得到所有操作在当前询问位置 x i x_i xi 处累计的高度,若该高度大于等于 y i y_i yi ,说明该询问的答案在操作 [ l , m i d ] [l,{\rm mid}] [l,mid] 里,把该询问扔进“左儿子询问区间”,否则扔进“右儿子询问区间”。由于询问位置是递增的,二元组首元素也是递增的,因此这个过程是线性的。

我们把 [ l 2 , r 2 ] [l_2,r_2] [l2,r2] 的询问分流后,用“左儿子询问区间”替换 [ l 2 , m d ] [l_2,md] [l2,md] ,“右儿子询问区间”替换 [ m d + 1 , r 2 ] [md+1,r_2] [md+1,r2] ,接下来递归 ( [ l , m i d ] , [ l 2 , m d ] ) \Big([l,{\rm mid}],[l_2,md]\Big) ([l,mid],[l2,md]) ( [ m i d + 1 , r ] , [ m d + 1 , r 2 ] ) \Big([{\rm mid}+1,r],[md+1,r_2]\Big) ([mid+1,r],[md+1,r2])

于是我们的算法瓶颈就在二元组序列 s t st st 的处理上,目前仍需要排序,使得整个程序复杂度是 O ( q log ⁡ 2 q ) O(q\log^2q) O(qlog2q) 的。我们需要砍掉一个 log ⁡ q \log q logq

我们发现,一个操作的两个二元组是恒定的,于是,可以一开始就将所有二元组排序,形成序列 S T ST ST ,然后操作中的 s t st st 可以通过 S T ST ST 的子串类似询问区间的分流得到。我们再多两个参数 l 3 , r 3 l_3,r_3 l3,r3 ,表示当前操作区间对应的二元组(子)序列 [ l 3 , r 3 ] [l_3,r_3] [l3,r3] ,然后扫描所有二元组,把来源种类小于等于 m i d {\rm mid} mid 的二元组归到“左序列”中,其余归到“右序列”,然后合并形成新序列,替换 [ l 3 , r 3 ] [l_3,r_3] [l3,r3]。设分界点为 m i mi mi [ l 3 , m i ] [l_3,mi] [l3,mi] [ m i + 1 , r 3 ] [mi+1,r_3] [mi+1,r3] 里的二元组是排好序的,而且这个分流也是线性的。我们要用的 s t st st 就是这时候的子序列 [ l 3 , m i ] [l_3,mi] [l3,mi]

时间复杂度 O ( q log ⁡ q ) O(q\log q) O(qlogq)

CODE

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<random>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 1000005
#define LL long long
#define ULL unsigned long long
#define DB double
#define lowbit(x) (-(x) & (x))
#define ENDL putchar('\n')
#define FI first
#define SE second
LL read() {
    LL f=1,x=0;int s = getchar(); 
    while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
    while(s >= '0' && s <= '9') {x = (x<<3) + (x<<1) + (s^48); s = getchar();}
    return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar('0'+(x%10));}
void putnum(LL x) {
    if(!x) {putchar('0');return ;}
    if(x<0) {putchar('-');x = -x;}
    return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}

int n,m,s,o,k;
int L[MAXN],R[MAXN],H[MAXN],X[MAXN],cna;
struct it{
	int x,id;
	LL y;
	it(){x=y=id=0;}
	it(int X,LL Y,int I){x=X;y=Y;id=I;}
}q[MAXN],q1[MAXN],q2[MAXN];
it st[MAXN<<1],s1[MAXN<<1],s2[MAXN<<1];
int tp;
int as[MAXN],lm[MAXN],cnq;
bool cmpq(it a,it b) {return a.x < b.x;}
void solve(int l,int r,int l2,int r2,int l3,int r3) {
	if(l == r) {
		int ll = L[l],rr = R[l],h = H[l];
		for(int i = l2;i <= r2;i ++) {
			if(ll <= q[i].x && rr >= q[i].x && h >= q[i].y) {
				as[q[i].id] = X[l];
			}
		}return ;
	}
	int mid = (l + r) >> 1;
	int ct1 = 0,ct2 = 0;
	for(int i = l3;i <= r3;i ++) {
		if(st[i].id <= mid) s1[++ ct1] = st[i];
		else s2[++ ct2] = st[i];
	}
	int md = l3 + ct1 - 1;
	for(int i = l3;i <= md;i ++) st[i] = s1[i-l3+1];
	for(int i = md+1;i <= r3;i ++) st[i] = s2[i-md];
	int j = l3,c1 = 0,c2 = 0;
	LL sm = 0;
	for(int i = l2;i <= r2;i ++) {
		int xx = q[i].x;
		while(j <= md && st[j].x <= xx) sm += st[j ++].y;
		if(q[i].y <= sm) {
			q1[++ c1] = q[i];
		}
		else {
			q[i].y -= sm;
			q2[++ c2] = q[i];
		}
	}
	int md2 = l2 + c1 - 1;
	for(int i = l2;i <= md2;i ++) q[i] = q1[i-l2+1];
	for(int i = md2+1;i <= r2;i ++)q[i] = q2[i-md2];
	solve(l,mid,l2,md2,l3,md);
	solve(mid+1,r,md2+1,r2,md+1,r3);
	return ;
}
int main() {
	freopen("concrete.in","r",stdin);
	freopen("concrete.out","w",stdout);
	n = read();m = read();
	for(int i = 1;i <= m;i ++) {
		k = read();
		if(k == 1) {
			cna ++;
			L[cna] = read();
			R[cna] = read();
			H[cna] = read();
			X[cna] = i;
			st[++ tp] = it(L[cna],H[cna],cna);
			st[++ tp] = it(R[cna]+1,-H[cna],cna);
		}
		else {
			cnq ++;
			q[cnq].x = read();
			q[cnq].y = read();
			q[cnq].id = cnq;
			lm[cnq] = i;
		}
	}
	sort(st + 1,st + 1 + tp,cmpq);
	sort(q + 1,q + 1 + cnq,cmpq);
	solve(1,cna,1,cnq,1,tp);
	for(int i = 1;i <= cnq;i ++) {
		if(!as[i] || as[i] > lm[i]) {
			AIput(0,'\n');
		}
		else AIput(as[i],'\n');
	}
	return 0;
}
posted @ 2021-11-04 17:52  DD_XYX  阅读(126)  评论(0编辑  收藏  举报