Given the finite
multi-set
A
of
n
pairs of integers, an another finite
multi-set
B
of
m
triples of integers, we define the product of
A
and
B
as a
multi-set
C=A∗B={⟨a,c,d⟩∣⟨a,b⟩∈A, ⟨c,d,e⟩∈B and b=e}
For each
⟨a,b,c⟩∈C
, its BETTER set is defined as
BETTERC(⟨a,b,c⟩)={⟨u,v,w⟩∈C∣⟨u,v,w⟩≠⟨a,b,c⟩, u≥a, v≥b, w≥c}
As a \textbf{multi-set} of triples, we define the TOP subset (as a multi-set as well) of
C
, denoted by
TOP(C)
, as
TOP(C)={⟨a,b,c⟩∈C∣BETTERC(⟨a,b,c⟩)=∅}
You need to compute the size of
TOP(C)
.
For each
As a \textbf{multi-set} of triples, we define the TOP subset (as a multi-set as well) of
You need to compute the size of
Each test case contains three lines. The first line contains two integers
The second line contains
which describe the multi-set
The third line contains
corresponding to the
2 5 9 1 1 2 2 3 3 3 3 4 2 1 4 1 2 2 1 4 1 1 1 3 2 3 2 2 4 1 2 2 4 3 3 2 3 4 1 3 3 4 2 7 2 7 2 7 1 4 7 2 3 7 3 2 7 4 1 7
Case #1: 5 Case #2: 12
题意是给你n个二元组a,b m个三元组c,d,e,让你找B==e的组成集合c(a,c,d)问这个集合中 a,c,d不全部大于等于其他的有几个。
要是就按b==e的全加进去,然后在二重循环比较肯定要超时的。
所以我们可以先处理a,b b相等时就选大的a,因为小的a最后肯定要被去掉的。
然后我们就按是否be相等建好集合。按a排序从小到大,从后往前找。
这样后面的a肯定大于前面的a 要是后面的c,d也大于等于前面的,那就肯定不符合了。所以就想到了二维树状数组。#include <iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int maxn=100005; int a[100005]; int num[100005]; int c[1005][1005]; struct node { int a,c,d; int num; }y[maxn]; int cmp(node q,node w) { if(q.a!=w.a)return q.a<w.a; else if(q.c!=w.c)return q.c<w.c; else return q.d<w.d; } int lowbit(int i) { return i&(-i); } int query(int x) { int sum=0; int i=y[x].c; while(i<1004) { int j=y[x].d; while(j<1004) { sum+=c[i][j]; j+=lowbit(j); //cout<<i<<" "<<j<<endl; } i+=lowbit(i); } return sum; } void update(int x) { int i=y[x].c; while(i>0) { int j=y[x].d; while(j>0) { c[i][j]++; j-=lowbit(j); } i-=lowbit(i); } } int main() { int t; cin>>t; int cc=1; while(t--) { int n,m; memset(c,0,sizeof(c)); memset(a,-1,sizeof(a)); //memset(num,0,sizeof(num)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { int a1,b; scanf("%d%d",&a1,&b); if(a[b]<a1) { a[b]=a1; //对于每个b记录最大的a1 num[b]=1; //更新他所对应的数量值 } else if(a[b]==a1) { num[b]++; } } int z=1; for(int i=1;i<=m;i++) { int c,d,e; scanf("%d%d%d",&c,&d,&e); if(a[e]==-1)continue; y[z].a=a[e]; y[z].c=c; y[z].d=d; y[z++].num=num[e]; //继承之前就重复的元素 } sort(y+1,y+z,cmp); //按三个值从小到大的顺序排序 int xx=z-1; z=1; int flag=0; y[z].a=y[z].a; y[z].c=y[z].c; y[z].d=y[z].d; y[z].num=y[z].num; for(int i=2;i<=xx;i++) { if(y[z].a==y[i].a&&y[z].d==y[i].d&&y[z].c==y[i].c) y[z].num+=y[i].num; else { flag=1; y[++z].a=y[i].a; y[z].c=y[i].c; y[z].d=y[i].d; y[z].num=y[i].num; } } long long ans=0; //out<<"kovkdfv"<<endl; if(flag) for(int i=z;i>=1;i--) { if(!query(i))ans+=(long long) y[i].num; update(i); } printf("Case #%d: %d\n",cc++,ans); } return 0; }