当前位置: 首页 > 工具软件 > Whiskey > 使用案例 >

DTOJ3704 威士忌(whiskey)

丌官高远
2023-12-01

题目

题目描述

Alan喝了假威士忌,想问你一个问题:
nvliu66推荐大家读三本书《百年孤独》、《城市发展史》、《美国大城市的生与死》(???)
三本书的总页数分别为 p , q , r p,q,r p,q,r
现有 n n nnvliu66的粉丝,作为nvliu66的粉丝,想必每本书都至少读过一页,其中第 i i i个粉丝读过 a i a_i ai页《百年孤独》、 b i b_i bi页《城市发展史》、 c i c_i ci页《美国大城市的生与死》 ( 1 ⩽ a i ⩽ p , 1 ⩽ b i ⩽ q , 1 ⩽ c i ⩽ r ) (1 \leqslant a_i \leqslant p,1 \leqslant b_i \leqslant q,1 \leqslant c_i \leqslant r) (1aip,1biq,1cir)
如果粉丝 x x x有不少于两本书阅读过的页数都严格多余粉丝 y y y,即当 a x > a y , b x > b y , c x > c y a_x>a_y,b_x>b_y,c_x>c_y ax>ay,bx>by,cx>cy 三个条件中有至少两个成立时,那么称 x x x y y y更“博闻强识”(???)
Alan作为nvliu66的粉丝,也决定去读 a 0 a_0 a0 页《百年孤独》、 b 0 b_0 b0页《城市发展史》、 c 0 c_0 c0页《美国大城市的生与死》 ( 1 ⩽ a 0 ⩽ p , 1 ⩽ b 0 ⩽ q , 1 ⩽ c 0 ⩽ r ) (1 \leqslant a_0 \leqslant p,1 \leqslant b_0 \leqslant q,1 \leqslant c_0 \leqslant r) (1a0p,1b0q,1c0r)
如果Alan n n n个粉丝都要博闻强识,那么他就会感到很奴比(???)
Alan想知道自己有多少种不同的读书方案使自己会很奴比,两个读书方案不同当且仅当存在一本书读取的页数不同

输入格式

第一行,四个整数 n , p , q , r n,p,q,r n,p,q,r
接下来 n n n行,每行三个整数 a i , b i , c i a_i,b_i,c_i ai,bi,ci

输出格式

一行,表示答案

样例

样例输入

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

样例输出

10

数据范围与提示

对于 30 % 30 \% 30%的数据, n , p , q , r ⩽ 100 n,p,q,r \leqslant 100 n,p,q,r100
对于 60 % 60 \% 60%的数据, n , p , q , r ⩽ 50000 n,p,q,r \leqslant 50000 n,p,q,r50000
对于 100 % 100 \% 100%的数据, n , p , q , r ⩽ 500000 n,p,q,r \leqslant 500000 n,p,q,r500000

题解

首先,我们先将这些粉丝按 a i a_i ai的大小来排序,然后我们枚举 a 0 a_0 a0的大小,有两种情况:

  1. 如果 a i > a 0 a_i>a_0 ai>a0,那我们就要要求 b > b i b>b_i b>bi并且 c > c i c>c_i c>ci,为了方便,我们可以先预处理求出 m a x b i maxb_i maxbi m a x c i maxc_i maxci(后缀最大值)
  2. 如果 a i < a 0 a_i<a_0 ai<a0,那我们就要要求 b > b i b>b_i b>bi c > c i c>c_i c>ci,所以我们把所有的 ( b i , c i ) (b_i,c_i) (bi,ci)数对转化为直角坐标系上的点,那么 ( b 0 , c 0 ) (b_0,c_0) (b0,c0)就不能在任何一个以 ( b i , c i ) (b_i,c_i) (bi,ci)组成的矩形中,又因为这些矩形的并集的 y y y是递减的,所以我们就可以用一棵线段树来维护这些矩形的并集的面积

附上代码:

#include<algorithm>
#include<cstdio>
using namespace std;
struct ppap
{
	int a,b,c;
}s[500010];
struct Segment_Tree
{
	int min,add;
	long long sum;
}t[2000010];
int n,p,q,r,maxb[500010],maxc[500010];
long long ans;
int cmp(const ppap &a,const ppap &b)
{
	return a.a<b.a;
}
void spread(int p,int l,int r)
{
	int mid=(l+r)/2;
	t[p*2].add=t[p*2+1].add=t[p*2].min=t[p*2+1].min=t[p].add,t[p*2].sum=(mid-l+1)*t[p].add,t[p*2+1].sum=(r-mid)*t[p].add,t[p].add=0;
}
int find(int p,int l,int r,int x)
{
	if(l==r) return (t[p].min<x?l:l+1);
	if(t[p].add) spread(p,l,r);
	int mid=(l+r)>>1;
	if(t[p*2].min<x) return find(p*2,l,mid,x);
	else return find(p*2+1,mid+1,r,x);
}
void change(int p,int l,int r,int L,int R,int d)
{
	if(L<=l&&r<=R){t[p].min=t[p].add=d,t[p].sum=(r-l+1)*d;return;}
	if(t[p].add) spread(p,l,r);
	int mid=(l+r)/2;
	if(L<=mid) change(p*2,l,mid,L,R,d);
	if(R>mid) change(p*2+1,mid+1,r,L,R,d);
	t[p].sum=t[p*2].sum+t[p*2+1].sum,t[p].min=min(t[p*2].min,t[p*2+1].min);
}
long long Ask(int p,int l,int r,int L,int R)
{
	if(L<=l&&r<=R) return t[p].sum;
	if(t[p].add) spread(p,l,r);
	int mid=(l+r)/2;
	long long ans=0;
	if(L<=mid) ans+=Ask(p*2,l,mid,L,R);
	if(R>mid) ans+=Ask(p*2+1,mid+1,r,L,R);
	return ans;
}
long long ask(int b,int c)
{
	int x=find(1,1,r,b);
	if(x<=c) return 1ll*(c-x+1)*b-Ask(1,1,r,x,c);
	return 0;
}
int main()
{
	freopen("whiskey.in","r",stdin);
	freopen("whiskey.out","w",stdout);
	scanf("%d%d%d%d",&n,&p,&q,&r);
	for(int i=1;i<=n;i++) scanf("%d%d%d",&s[i].a,&s[i].b,&s[i].c);
	sort(s+1,s+n+1,cmp);
	for(int i=n;i;i--) maxb[i]=max(maxb[i+1],s[i].b),maxc[i]=max(maxc[i+1],s[i].c);
	for(int i=1;i<=n;i++){
		long long Ans=ask(q,r)-ask(maxb[i],r)-ask(q,maxc[i])+ask(maxb[i],maxc[i]);
		ans+=Ans*(s[i].a-s[i-1].a);
		int x=find(1,1,r,s[i].b);
		if(x<=s[i].c) change(1,1,r,x,s[i].c,s[i].b);
	}
	printf("%lld",ans+1ll*(p-s[n].a)*ask(q,r));
}
 类似资料: