NC19427 換個角度思考
阿新 • • 發佈:2020-07-19
連結:https://ac.nowcoder.com/acm/problem/19427
來源:牛客網
題目描述
給定一個序列,有多次詢問,每次查詢區間裡小於等於某個數的元素的個數
即對於詢問 (l,r,x),你需要輸出 ∑i=lr[ai≤x]\sum_{i=l}^{r}[a_i \le x]∑i=lr[ai≤x] 的值
其中 [exp] 是一個函式,它返回 1 當且僅當 exp 成立,其中 exp 表示某個表示式
輸入描述:
第一行兩個整數n,m 第二行n個整數表示序列a的元素,序列下標從1開始標號,保證1 ≤ ai ≤ 105 之後有m行,每行三個整數(l,r,k),保證1 ≤ l ≤ r ≤ n,且1 ≤ k ≤ 105
輸出描述:
對於每一個詢問,輸出一個整數表示答案後回車
思路
根據題意我們知道要詢問的是區間內小於等於k的個數。
首先我們想區間問題的處理一般會選擇樹或者樹狀陣列,然後我們去思考如何去解決這個問題。
詢問中\((l,r,k)\)詢問在區間內小於等於\(k\)的個數,我們考慮到可以離線處理
我們將原陣列的結構體和詢問的結構體排序後,按詢問的\(k\)的大小進行插入,每次插入的都是小於詢問的\(k\),然後去區間和求解。
然後樹狀陣列就可以在\(n\log n\)的複雜度內求出答案。
#include<bits/stdc++.h> #define INF 0x3f3f3f3f #define DOF 0x7f7f7f7f #define endl '\n' #define mem(a,b) memset(a,b,sizeof(a)) #define debug(case,x); cout<<case<<" : "<<x<<endl; #define open freopen("ii.txt","r",stdin) #define close freopen("oo.txt","w",stdout) #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define pb push_back using namespace std; typedef long long ll; typedef pair<int, int> pii; typedef pair<long long, long long> PII; const int maxn = 1e6+10; int n,m; //int a[maxn]; int d[maxn]; int ans[maxn]; struct node{ int a,id; bool operator<(const node x)const{ if(id==x.id) return id<x.id; else return a<x.a; } }node[maxn]; struct section{ int l,r,k,id; bool operator<(const section x)const { return k<x.k; } }section[maxn]; inline int lowbit(int x){return x&(-x);} int get_sum(int x){ int ans=0; while(x){ ans+=d[x];x-=lowbit(x); } return ans; } void update(int x,int y){ while(x<=n){ d[x]+=y;x+=lowbit(x); } } int main(){ cin>>n>>m; for(int i=1;i<=n;++i){ cin>>node[i].a; node[i].id=i; } int l,r,k; for(int i=1;i<=m;++i){ cin>>l>>r>>k; section[i]={l,r,k,i}; } sort(node+1,node+1+n); sort(section+1,section+1+m); for(int i=1,j=1;i<=m;++i){ int val=section[i].k; for(;j<=n&&node[j].a<=val;++j){ update(node[j].id,1); } ans[section[i].id]=get_sum(section[i].r)-get_sum(section[i].l-1); } for(int i=1;i<=m;++i){ cout<<ans[i]<<endl; } }