判斷一個區間中比某個數小的數的個數
阿新 • • 發佈:2018-12-22
題目如下:
給定一個序列,有多次詢問,每次查詢區間裡小於等於某個數的元素的個數
即對於詢問 (l,r,x),你需要輸出 的值
其中 [exp] 是一個函式,它返回 1 當且僅當 exp 成立,其中 exp 表示某個表示式
這個題可以使用兩種方法來解決:
樹狀陣列:由於每一個數都有其地址的編號,所以先記錄沒個數的編號,然後對這組數進行排序,對於(l, r,x)進行對多次輸入也分別記錄他們的地址,這樣就可以分別輸出符合條件的數,然後就是樹狀陣列的基本更新和求和操作。每一次比較的是比較val,但是更新的是他的編號,這樣就可以直接查詢不怕出現錯誤;
程式碼如下:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<set> #include<map> #include<queue> #define pi acos(-1) #define e exp(1) #define For(i, a, b) for(int (i) = (a); (i) <= (b); (i) ++) #define Bor(i, a, b) for(int (i) = (b); (i) >= (a); (i) --) #define max(a,b) (((a)>(b))?(a):(b)) #define min(a,b) (((a)<(b))?(a):(b)) #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 #define eps 1e-7 #define INF 0x3f3f3f3f #define inf -2100000000 using namespace std; typedef unsigned long long ull; typedef long long ll; const int maxn = 1e5 + 10; const double EPS = 1e-10; const ll p = 1e7+9; const ll mod = 1e9+7; ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} inline int read(){ int ret=0,f=0;char ch=getchar(); while(ch>'9'||ch<'0') f^=ch=='-',ch=getchar(); while(ch<='9'&&ch>='0') ret=ret*10+ch-'0',ch=getchar(); return f?-ret:ret; } int n, m; struct node{ int l, r, val; int id; }a[maxn],b[maxn]; int sum[maxn]; int ans[maxn]; int lowbit(int rt){ return rt & (-rt); } void add(int rt){ while(rt <= n){ sum[rt] += 1; rt += lowbit(rt); } return ; } int Sum(int rt){ int ans = 0; while(rt > 0){ ans += sum[rt]; rt -= lowbit(rt); } return ans; } bool cmp(node x, node y){ return x.val < y.val; } int main(){ ios::sync_with_stdio(false); cin >> n >> m; for(int i = 1; i <= n; i++){ cin >> a[i].val; a[i].id = i; } sort(a+1, a+n+1, cmp); for(int i = 1; i <= m; i++){ cin >> b[i].l >> b[i].r >> b[i].val; b[i].id = i; } sort(b+1, b+1+m, cmp); int q = 1; for(int i = 1; i <= m; i++){ while(a[q].val <= b[i].val && q <= n ){ add(a[q].id); q++; } ans[b[i].id] = Sum(b[i].r) - Sum(b[i].l-1); } for(int i = 1; i <= m; i++){ cout << ans[i] << endl; } return 0; }
線段樹的方法:
線段樹和樹狀陣列的操作是一樣是的,都是值比較大小然後把他的地址更新:然後使用區間求和得到值:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<set> #include<map> #include<queue> #define pi acos(-1) #define e exp(1) #define For(i, a, b) for(int (i) = (a); (i) <= (b); (i) ++) #define Bor(i, a, b) for(int (i) = (b); (i) >= (a); (i) --) #define max(a,b) (((a)>(b))?(a):(b)) #define min(a,b) (((a)<(b))?(a):(b)) #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 #define eps 1e-7 #define INF 0x3f3f3f3f #define inf -2100000000 using namespace std; typedef unsigned long long ull; typedef long long ll; const int maxn = 1e5 + 10; const double EPS = 1e-10; const ll p = 1e7+9; const ll mod = 1e9+7; ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} inline int read(){ int ret=0,f=0;char ch=getchar(); while(ch>'9'||ch<'0') f^=ch=='-',ch=getchar(); while(ch<='9'&&ch>='0') ret=ret*10+ch-'0',ch=getchar(); return f?-ret:ret; } struct node{ int l,r,val,id; }b[maxn],a[maxn]; int ans[maxn],tree[maxn << 2]; bool cmp(node a, node b){ return a.val < b.val; } void push_up(int rt){ tree[rt] = tree[rt << 1] + tree[rt << 1 | 1]; } void update(int p, int l, int r, int rt){ if(l == r){ tree[rt]++; return ; } int mid = (l+r) >> 1; if(p <= mid) update(p, lson); else update(p, rson); push_up(rt); } int query(int a,int b,int l,int r,int rt){ if(a<=l && r<=b){ return tree[rt]; } int mid = (l+r) >> 1; int ans = 0; if(a <= mid) ans += query(a, b, lson); if(b > mid)ans += query(a, b, rson); return ans; } int main(){ int n,m; cin >> n >> m; for(int i = 1; i <= n; i++){ cin >> a[i].val; a[i].id = i; } sort(a + 1, a + n + 1, cmp); for(int i = 1; i <= m; i++){ cin >> b[i].l >> b[i].r >> b[i].val; b[i].id = i; } sort(b + 1,b + m + 1, cmp); int q = 1; for(int i = 1; i <= m; i++){ while(q <= n && a[q].val <= b[i].val){ update(a[q].id, 1, n, 1); //cout << "+++" << a[q].id << " " << tree[a[q].id] << endl; q++; } ans[b[i].id] = query(b[i].l, b[i].r, 1, n, 1); } for(int i=1; i <= m; i++){ cout<<ans[i]<<endl; } }
腦子要變通,不能太死板: