題目描述:
時間限制:C/C++ 3秒,其他語言6秒
空間限制:C/C++ 256M,其他語言512M
爲了不斷優化推薦效果,今日頭條每天要存儲和處理海量數據。假設有這樣一種場景:我們對用戶按照它們的註冊時間先後來標號,對於一類文章,每個用戶都有不同的喜好值,我們會想知道某一段時間內註冊的用戶(標號相連的一批用戶)中,有多少用戶對這類文章喜好值爲k。因爲一些特殊的原因,不會出現一個查詢的用戶區間完全覆蓋另一個查詢的用戶區間(不存在L1<=L2<=R2<=R1)。
思路:
我的思路:
因爲詢問區間保證了不會出現覆蓋,那麼如果將詢問區間對左端點排序的話,就會出現下圖這樣
也就是說,如果對左端點排序,右端點一定是不斷變大的。因爲l1<=l2,所以r2>r1一定成立,否則就會與條件衝突。
所以我們維護雙指針,用sum[maxn]標記離散化後的數i在已經掃過的區域內出現的次數的和。
右指針右移,sum[a[i]]++,左指針右移,sum[a[i]]--,這樣就像是一個前綴和的性質,掃一遍複雜度O(n),還有離散化操作,應該是O(nlogn)的複雜度。
但是我只過了70%,沒有檢查出錯,可能是數據隨機並沒有滿足題目中的條件,也希望各位大佬幫我查查錯。
#include <bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
vector<int>v;
int getid(int cur){
return lower_bound(v.begin(),v.end(),cur)-v.begin()+1;
}
struct Node{
int l,r;
int k;
int id;
}node[maxn];
int a[maxn];
int sum[maxn];
int ans[maxn];
int cmp(const Node a,const Node b){
return a.l<b.l||(a.l==b.l&&a.r<b.r);
}
signed main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
v.push_back(a[i]);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d%d%d",&node[i].l,&node[i].r,&node[i].k);
node[i].id=i;
}
sort(node+1,node+q+1,cmp);
int l=1,r=1;
int cur=1;
while(cur<=q){
while(r<=node[cur].r){
sum[getid(a[r])]++;
r++;
}
while(l<node[cur].l){
sum[getid(a[l])]--;
l++;
}
int now=sum[getid(node[cur].k)];
ans[node[cur].id]=now;
cur++;
}
for(int i=1;i<=q;i++){
printf("%d\n",ans[i]);
}
return 0;
}
大佬的思路:
簡單明瞭,維護一個值k的出現序列vector,如果有詢問l,r,k,直接在vector中二分到l-1和r這個區間,看這個區間的長度有多長,就說明這個區間內有多少個k,不得不說這是我見過最簡單明瞭的思路了。
#include <bits/stdc++.h>
using namespace std;
map<int, vector<int> >ma;
int n, q, t;
int l, r, k;
int solve(int l, int r, int k) {
if (ma[k].size() == 0) return 0;
auto it1 = lower_bound(ma[k].begin(), ma[k].end(), l);
auto it2 = upper_bound(ma[k].begin(), ma[k].end(), r);
return it2 - it1;
}
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> t;
ma[t].push_back(i);
}
cin >> q;
for (int i = 0; i < q; ++i) {
cin >> l >> r >> k;
cout << solve(l, r, k) << endl;
}
return 0;
}