西西打pk 解题报告
简要题意
给定 \(n\) 个三元组 \((a_i,b_i,c_i)\),值域为 \([1,m]\)。询问在值域内有多少三元组 \((A,B,C)\) ,满足 \(\exists_{i \in [1,n]} (A > a_i) \lor (B > b_i) \lor (C > c_i)\)。
数据范围:\(n \le 10^5,m \le 10^5\)。
分析
限制太弱了,考虑求不合法的数量。“三个元素都小于一个三元组“这个限制很强,很好统计。
于是题目转化为一个三维偏序问题。注意到偏序条件都是一段前缀,于是考虑第一位排序后,用第二位为下标的数据结构维护第三位可以取得的最大值。
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define Inf (1ll<<60)
#define For(i,s,t) for(int i=s;i<=t;++i)
#define Down(i,s,t) for(int i=s;i>=t;--i)
#define ls (i<<1)
#define rs (i<<1|1)
#define bmod(x) ((x)>=mod?(x)-mod:(x))
#define lowbit(x) ((x)&(-(x)))
#define End {printf("NO\n");exit(0);}
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
inline void ckmx(int &x,int y){x=(x>y)?x:y;}
inline void ckmn(int &x,int y){x=(x<y)?x:y;}
inline void ckmx(ll &x,ll y){x=(x>y)?x:y;}
inline void ckmn(ll &x,ll y){x=(x<y)?x:y;}
inline int min(int x,int y){return x<y?x:y;}
inline int max(int x,int y){return x>y?x:y;}
inline ll min(ll x,ll y){return x<y?x:y;}
inline ll max(ll x,ll y){return x>y?x:y;}
inline int read(){
register int x=0,f=1;
char c=getchar();
while(c<'0' || '9'<c) f=(c=='-')?-1:1,c=getchar();
while('0'<=c && c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
return x*f;
}
void write(int x){
if(x>=10) write(x/10);
putchar(x%10+'0');
}
const int N=2e5+100;
int n,m;
ll ans;
struct Node{int x,y,z;}a[N];
bool cmp(Node x,Node y){return x.x>y.x;}
struct Tree{int l,r,mn,tag;ll val;}t[N<<2];
void push_up(int i){
t[i].val=t[ls].val+t[rs].val;
t[i].mn=min(t[ls].mn,t[rs].mn);
}
void upd(int i,int x){
t[i].val=1ll*(t[i].r-t[i].l+1)*x;
t[i].mn=t[i].tag=x;
}
void push_down(int i){
if(t[i].tag)
upd(ls,t[i].tag),upd(rs,t[i].tag),t[i].tag=0;
}
void build(int i,int l,int r){
t[i].l=l,t[i].r=r,t[i].tag=0;
if(l==r){
t[i].mn=t[i].val=0;
return;
}
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
push_up(i);
}
void update(int i,int l,int r,int x){
if(l<=t[i].l && t[i].r<=r){
upd(i,x);
return;
}
push_down(i);
int mid=t[i].l+t[i].r>>1;
if(l<=mid) update(ls,l,r,x);
if(mid<r) update(rs,l,r,x);
push_up(i);
}
int query(int i,int l,int r,int x){
if(t[i].mn>x) return -1;
if(t[i].l==t[i].r) return t[i].l;
push_down(i);
int mid=t[i].l+t[i].r>>1;
if(l<=t[i].l && t[i].r<=r)
return t[ls].mn<=x ? query(ls,l,r,x) :query(rs,l,r,x);
int res;
if(l<=mid && (res=query(ls,l,r,x))!=-1) return res;
return query(rs,l,r,x);
}
int main()
{
#if !ONLINE_JUDGE
freopen("pk.in","r",stdin);
freopen("pk.out","w",stdout);
#endif
while(true){
n=read(),m=read();
if(!n && !m) return 0;
For(i,1,n) a[i].x=read(),a[i].y=read(),a[i].z=read();
sort(a+1,a+n+1,cmp);
ans=1ll*m*m*m;
int ind=1;
build(1,1,m);
Down(i,m,1){
while(ind<=n && a[ind].x==i){
int pos=query(1,1,a[ind].y,a[ind].z);
if(pos!=-1)
update(1,pos,a[ind].y,a[ind].z);
++ind;
}
ans-=t[1].val;
}
printf("%lld\n",ans);
}
return 0;
}