JOISC 2019 Day1 A 試験 (Examination)

\(\texttt{Description}\)

洛谷题目链接

AtCoder 题目链接

PDF 题面

  • \(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\) 倍空间,因为二元组和询问一起离散化。

  • 可以用指令集加快代码效率。

  • 我是使用 setmap 两个 STL 来实现离散化的。

  • 我是使用 pb_ds 库中的 rb_tree_tag(红黑树)来实现平衡树的。码量较小,理论效率较优,但是常数较大。

Submission

$\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]);
    }
}
posted @ 2023-03-11 11:36  lzyqwq  阅读(25)  评论(0)    收藏  举报