HDU 4417 Super Mario--離線樹狀陣列、劃分樹、線段樹
阿新 • • 發佈:2019-01-28
題意:詢問區間[l,r]內有幾個數字小於h
思路:對於每次詢問H,L,R,僅需要考慮比H小的hi在L,R範圍內的個數;
為了避免比H大的hi的影響,可以想到對詢問H,和hi進行排序
在詢問H時,僅將比H小的hi插入到樹狀陣列中
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define MAXN 100002 #define lowbit(i) (i & (-i)) int prefix[MAXN],ans[MAXN]; struct Interval { int h,index; bool operator < (const Interval & inter)const{ return h < inter.h; } }interval[MAXN]; struct Query { int l,r,h,id; bool operator < (const Query & qu)const{ return h < qu.h; } }query[MAXN]; int sum(int i) { int total = 0; while(i) { total += prefix[i]; i -= lowbit(i); } return total; } void modify(int i,int maxn,int key) { while(i <= maxn) { prefix[i] += key; i += lowbit(i); } } int main() { int _,n,m,ql,qr,val; scanf("%d",&_); for(int kcase = 1;kcase <= _;kcase++) { printf("Case %d:\n",kcase); scanf("%d%d",&n,&m); memset(prefix,0,sizeof(prefix)); for(int i = 1;i <= n;i++) { scanf("%d",&interval[i].h); interval[i].index = i; } for(int i = 1;i <= m;i++) { scanf("%d%d%d",&query[i].l,&query[i].r,&query[i].h); query[i].id = i; } sort(interval + 1,interval + n + 1); sort(query + 1,query + m + 1); for(int j = 1,i = 1;i <= m;i++) { while(j != m + 1 && interval[j].h <= query[i].h) { modify(interval[j].index,n,1); j++; } ans[query[i].id] = sum(query[i].r + 1) - sum(query[i].l); } for(int i = 1;i <= m;i++) printf("%d\n",ans[i]); } }
也可以用二分加劃分樹來做
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define MAXN 100001 #define LOG 20 int sorted[MAXN] , part_tree[MAXN][LOG] , left_cnt[MAXN][LOG]; int ql,qr; void build(int l,int r,int deep) { if(l == r)return; int mid = l + r >> 1 , same = left_cnt[0][deep] = 0; for(int i = mid;i >= l;i--) if(sorted[mid] == sorted[i])same++; else break; int lcnt = l , rcnt = mid + 1; for(int i = l;i <= r;i++) { if(part_tree[i][deep] < sorted[mid]) part_tree[lcnt++][deep + 1] = part_tree[i][deep]; else if(part_tree[i][deep] == sorted[mid] && same) { part_tree[lcnt++][deep + 1] = part_tree[i][deep]; same--; } else part_tree[rcnt++][deep + 1] = part_tree[i][deep]; left_cnt[i][deep] = lcnt - l + left_cnt[l - 1][deep]; } build(l,mid,deep + 1) , build(mid + 1,r,deep + 1); } int query(int l,int r,int deep,int ql,int qr,int kth) { if(ql == qr)return part_tree[ql][deep]; int mid = l + r >> 1; int lcnt = left_cnt[qr][deep] - left_cnt[ql - 1][deep]; if(lcnt >= kth) { ql = l + left_cnt[ql - 1][deep] - left_cnt[l - 1][deep]; qr = ql + lcnt - 1; return query(l,mid,deep + 1,ql,qr,kth); } else { qr += left_cnt[r][deep] - left_cnt[qr][deep]; ql += left_cnt[r][deep] - left_cnt[ql - 1][deep]; return query(mid + 1,r,deep + 1,ql,qr,kth - lcnt); } } int binary(int val,int n) { int l = 1 , r = qr - ql + 1; if(query(1,n,0,ql + 1,qr + 1,1) > val)return 0; while(l < r) { int mid = l + r + 1 >> 1; if(query(1,n,0,ql +1,qr + 1,mid) <= val)l = mid; else r = mid - 1; } return r; } int main() { int _,n,m,kth,val; scanf("%d",&_); for(int kcase = 1;kcase <= _;kcase++) { printf("Case %d:\n",kcase); scanf("%d%d",&n,&m); for(int i = 1;i <= n;i++) { scanf("%d",&part_tree[i][0]); sorted[i] = part_tree[i][0]; } sort(sorted + 1,sorted + n + 1); build(1,n,0); while(m--) { scanf("%d%d%d",&ql,&qr,&val); int ans = binary(val,n); printf("%d\n",ans); } } }
線段樹每個節點維護一段有序序列
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<vector> using namespace std; #define MAXN 100002 const int root = 1; vector<int>vec[MAXN << 2]; int h[MAXN],ql,qr; void build(int l,int r,int cnt) { vec[cnt].clear(); for(int i = l;i <= r;i++) vec[cnt].push_back(h[i]); sort(vec[cnt].begin(),vec[cnt].end()); int mid = l + r >> 1; if(l == r)return; build(l,mid,cnt << 1); build(mid + 1,r,cnt << 1 | 1); } int query(int l,int r,int cnt,int key) { if(ql <= l && r <= qr) return upper_bound(vec[cnt].begin(),vec[cnt].end(),key) - vec[cnt].begin(); int mid = l + r >> 1 , ret = 0; if(ql <= mid)ret = query(l,mid,cnt << 1,key); if(qr >= mid + 1)ret += query(mid + 1,r,cnt << 1 | 1,key); return ret; } int main() { int _,n,m,val; scanf("%d",&_); for(int kcase = 1;kcase <= _;kcase++) { printf("Case %d:\n",kcase); scanf("%d%d",&n,&m); for(int i = 1;i <= n;i++) scanf("%d",&h[i]); build(1,n,root); for(int i = 1;i <= m;i++) { scanf("%d%d%d",&ql,&qr,&val); ql++ , qr++; int ans = query(1,n,root,val); printf("%d\n",ans); } } }