JOISC 2019 Day1 A 試験 (Examination)
\(\texttt{Description}\)
有 \(n\) 个二元组 \((a_i,b_i)\) 和 \(q\) 个询问 \((x_j,y_j,z_j)\),每个询问求满足 \(a_i\ge x_j\),\(b_i\ge y_j\),\(a_i+b_i\ge z_j\) 的二元组个数。
\(n,q\le 10^5\),\(a_i,b_i,x_j,y_j\le 10^9\),\(z_j\le 2\times 10^9\)。
\(\texttt{Solution}\)
三维偏序模板题,考虑使用权值树状数组套平衡树。
先对于 \(b_i\) 和 \(y_j\) 离散化,开一棵权值树状数组,内部嵌套平衡树。
再把所有信息按照 \(a_i\) 和 \(x_j\) 从大到小排序,使得每个询问统计的都是 \(\ge x_j\) 的贡献。若相同,则把二元组排在前,因为这些二元组是满足 \(a_i\ge x_j\) 的,可能会产生贡献(若没有则会在树套树中被舍去,所以要排在前)。
对于每个二元组,把 \(a_i+b_i\) 插入到自己和祖先的平衡树上。注意插入一个二元组,用第二元来维护可重。
对于每个询问,查询 \([1,y_j]\) 的平衡树中,\([z_j,\infty]\) 中的元素个数。由于没有上界,可以用整棵树的大小减去 \(<z_j\) 的个数。树状数组前缀查询即可。
时间复杂度 \(\mathcal{O}((n+q)\log^2n)\),空间复杂度 \(\mathcal{O}(n\log n)\)。可以在被 cdq 分治吊打的同时接受,当然还是可以吊打权值树状数组套动态开点线段树的。
\(\texttt{Code}\)
代码实现细节:
-
注意权值树状数组开 \(2\) 倍空间,因为二元组和询问一起离散化。
-
可以用指令集加快代码效率。
-
我是使用
set和map两个 STL 来实现离散化的。 -
我是使用
pb_ds库中的rb_tree_tag(红黑树)来实现平衡树的。码量较小,理论效率较优,但是常数较大。
$\texttt{Click for Code}$
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#define g __gnu_pbds
#define N 100005
#define pii pair<int,int>
#define tp make_pair
using namespace std;
int n,q,lsh,ans[N],cnt;
set<int>s;
map<int,int>mp;
g::tree<pii,g::null_type,less<pii>,g::rb_tree_tag,g::tree_order_statistics_node_update>bit[N<<1];
struct query{
int a,b,c,id;
query(){
a=b=c=id=0;
}
}p[N<<1];
void modify(int x,int k){
for(int i=x;i<=lsh;i+=i&-i){
bit[i].insert(tp(k,++cnt));
}
}
int qnum(int x,int k){
int ret=0;
for(int i=x;i;i-=i&-i){
ret+=bit[i].size()-bit[i].order_of_key(tp(k,0));
}
return ret;
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i){
scanf("%d%d",&p[i].a,&p[i].b);
s.insert(-p[i].b);//取反实现大的在前
p[i].c=p[i].a+p[i].b;
}
for(int i=1;i<=q;++i){
scanf("%d%d%d",&p[n+i].a,&p[n+i].b,&p[n+i].c);
s.insert(-p[n+i].b);
p[n+i].id=i;
}
for(int i:s){
mp[-i]=++lsh;
}
for(int i=1;i<=n+q;++i){
p[i].b=mp[p[i].b];
}
sort(p+1,p+1+n+q,[](query u,query v){return u.a^v.a?u.a>v.a:u.id<v.id;});
for(int i=1;i<=n+q;++i){
if(p[i].id){
ans[p[i].id]=qnum(p[i].b,p[i].c);
}else{
modify(p[i].b,p[i].c);
}
}
for(int i=1;i<=q;++i){
printf("%d\n",ans[i]);
}
}

浙公网安备 33010602011771号