题意:
有二元组(a,b),三元组(c,d,e)。当b == e时它们能构成(a,c,d)。
然后,当不存在(u,v,w)!=(a,b,c)且u>=a,v>=b,w>=c时,则是一个better集合里的元素。
问这个better集合有几个元素
思路:
注意到数据范围
对于 N 个二元组(a,b), M 个三元组(c,d,e)
N,M≤1e5
ai,bi≤1e5
ci,di≤1e3 ei≤1e5
假设所有bi和ei都相等
简单的两两组合会组合出1e5*1e5种 (a,c,d)
但考虑到条件:
求出所有(u,v,w)!=(a,b,c)且u>=a,v>=b,w>=c
有对于所有的 (a,b) 若存在 bi==bj 只有ai >= aj
的点对才有可能组成新的better (a,c,d)
即对于一类 bx 或 ex只会存在一个有效的ax
即对于任意一个三元组(c,d,e)只会有一个ax与之组合为新的(a,c,d)
故至多有1e5个可能的better(a,c,d)
那么问题就变成了在1e5(a,c,d)中找better
对于1e5个可能的better(a,c,d)
考虑到条件:
求出所有(u,v,w)!=(a,c,d)且u>=a,v>=c,w>=d
我们可将其按a大在前的顺序排序
对于之后的每个(a,c,d)都可以保证u>=a
那么问题就变成了在1e5(c,d)中找better
考虑到ci,di≤1e3
我们可以利用线段树维护对于每一种ci对应的最大值di
做1e5次区间查询和单点更新
对于每种(ci,di)先查询 [c,max(ci)]是否存在 dj>=di
若存在
则说明所有的(ci,di)(一种(ci,di)可能不止有一个)都是better
查询后再更新ci对应的最大值di即可
代码:
#include <bits/stdc++.h>
using namespace std;
#define ls l,mid,rt*2
#define rs mid+1,r,rt*2+1
#define sf l,r,rt
const int MAXN=1e3+100;
const int MAXNN=1e5+5;
typedef struct Node{
int x,y,z;
bool operator < (const Node &a)const{
if(x==a.x) return y==a.y?z>a.z:y>a.y;
return x>a.x;
}
}Node;
int tree[4*MAXN],fast[MAXN],st,en,v,ans,fans;
int t[MAXNN],cnt[MAXNN];
vector <Node> a[MAXNN];
map <Node,int> mp;
void build(int l,int r,int rt){
tree[rt]=0;
if(l==r){fast[l]=rt;return;}
int mid=(l+r)/2;
build(ls);
build(rs);
}
void update(int rt){
while(rt!=0&&tree[rt]<v){
tree[rt]=v;
rt/=2;
}
}
void query(int l,int r,int rt){
if(st>r||en<l||tree[rt]<=ans) return ;
if(st<=l&&r<=en) ans=tree[rt];
int mid=(l+r)/2;
query(ls);
query(rs);
}
void ini(){
for(int i=1;i<MAXNN-1;i++)
t[i]=cnt[i]=0,a[i].clear();
mp.clear();
en=-1;
fans=0;
}
int main()
{
int T,n,m,x,y,z;
scanf("%d",&T);
for(int Case=1;Case<=T;Case++){
ini();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d",&x,&y);
if(t[y]<x) t[y]=x,cnt[y]=1;
else if(t[y]==x) cnt[y]++;
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
if(t[z]!=0){
if(!mp[{t[z],x,y}])
a[t[z]].push_back({t[z],x,y});
mp[{t[z],x,y}]+=cnt[z];
en=max(en,x);
}
}
build(1,en,1);
int len;
for(int i=MAXNN-1;i>0;i--){
len=a[i].size();
if(len){
sort(a[i].begin(),a[i].end());
for(int j=0;j<len;j++){
ans=0;st=a[i][j].y;
query(1,en,1);
if(ans<a[i][j].z)
fans+=mp[a[i][j]];
v=a[i][j].z;
update(fast[a[i][j].y]);
}
}
}
printf("Case #%d: %d\n",Case,fans);
}
}