【poj 2828】 Buy Tickets(线段树/树状数组)
对于第i个人的位置id 其实就是找当前队列第id个空位置
例如第一组样例
4 0 77 1 51 1 33 2 69
给出下标从0开始 不好做 所以把下标统一后移一位
69->333->2
当51->2时 位置1可用 位置2.3被分配了 所以给51位置4
77->1
用线段树很容易写 找到从头开始的第k个空位置
代码如下:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; int bit[800800]; int ans[200200]; //初始化n个空位 void init(int site,int l,int r) { if(l == r) { bit[site] = 1; return; } int mid = (l+r)>>1; init(site<<1,l,mid); init(site<<1|1,mid+1,r); bit[site] = bit[site<<1]+bit[site<<1|1]; } //找第data个空位 int Search(int site,int l,int r,int data) { // printf("%d %d %d\n",l,r,data); //第data个空位肯定在当前遍历的子树中 剩余空位-- bit[site]--; //l == r说明遍历到叶子 也就是找到了第data个空位 if(l == r) return l; int mid = (l+r)>>1; //左树的位置不够 在右树中找第(data-(左树空位置))个空位置 if(bit[site<<1] < data) { return Search(site<<1|1,mid+1,r,data-bit[site<<1]); } //否则只直接在左树找第data个空位置 else { return Search(site<<1,l,mid,data); } } pair <int,int> p[200200]; int main() { int n; while(~scanf("%d",&n)) { init(1,1,n); for(int i = 0; i < n; ++i) { scanf("%d%d",&p[i].first,&p[i].second); } for(int i = n-1; i >= 0; --i) { // int tmp = Search(1,1,n,p[i].first+1); // puts("-------"); // printf("%d\n",tmp); ans[Search(1,1,n,p[i].first+1)] = p[i].second; } for(int i = 1; i <= n; ++i) { if(i != 1) putchar(' '); printf("%d",ans[i]); } puts(""); } return 0; }
树状数组两种做法 不过核心都跟线段树一样 找第k个空位
第一种就是二分 找第一个id 满足 前id项和==k
跟线段树的思想类似
直接上代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; int bit[200200]; int n; int Lowbit(int x) { return x&(-x); } void Add(int x,int data) { while(x <= n) { bit[x] += data; x += Lowbit(x); } } int Sum(int x) { int ans = 0; while(x > 0) { ans += bit[x]; x -= Lowbit(x); } return ans; } pair <int,int> p[200200]; int ans[200200]; int main() { int l,r,c; while(~scanf("%d",&n)) { for(int i = 0; i < n; ++i) { scanf("%d%d",&p[i].first,&p[i].second); p[i].first++; } for(int i = 1; i <= n; ++i) Add(i,1); for(int i = n-1; i >= 0; --i) { l = 1, r = n; c = -1; while(l <= r) { int mid = (l+r)>>1; int tmp = Sum(mid); if(tmp >= p[i].first) { if(tmp == p[i].first) c = mid; r = mid-1; } else l = mid+1; } ans[c] = p[i].second; Add(c,-1); } for(int i = 1; i <= n; ++i) { if(i != 1) putchar(' '); printf("%d",ans[i]); } puts(""); } return 0; }
代码如下:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; int bit[200200]; int n; int Lowbit(int x) { return x&(-x); } void Add(int x,int data) { while(x <= n) { bit[x] += data; x += Lowbit(x); } } int Sum(int x) { int ans = 0; while(x > 0) { ans += bit[x]; x -= Lowbit(x); } return ans; } int findk(int data) { int id = 0; for(int i = 17; i >= 0; --i) { id ^= 1<<i; if(id <= n && data > bit[id]) data -= bit[id]; else id ^= 1<<i; } return id+1; } pair <int,int> p[200200]; int ans[200200]; int main() { int l,r,c; while(~scanf("%d",&n)) { for(int i = 0; i < n; ++i) { scanf("%d%d",&p[i].first,&p[i].second); p[i].first++; } for(int i = 1; i <= n; ++i) Add(i,1); for(int i = n-1; i >= 0; --i) { c = findk(p[i].first); ans[c] = p[i].second; Add(c,-1); } for(int i = 1; i <= n; ++i) { if(i != 1) putchar(' '); printf("%d",ans[i]); } puts(""); } return 0; }