POJ2828 Buy Tickets
題意:插隊問題;
關鍵:如何插入這幾個節點,每個節點儲存什么信息。
類型:很基本的單點更新線段樹
思路:這題想到了就水了,數據逆着插入,最先插入的一個數據的位置明顯是題目給定的位置,可以確定,然后插入的幾個數根據的位置前面插入的數據來決定,
用sum[]數組表示改線段空位置的個數,滿足 pos<=sum[rt<<1](即左兒子的空位多於插入數的位置序號)就訪問左兒子,否則訪問右兒子
(訪問右節點的時候注意pos要修改,改為pos-sum[rt],即整個線段的第pos個空位,在下一個右兒子那的第pos-sum[rt]個空位)。
對自己的總結: 剛學線段樹,誒,這題刷了一下午,看來線段樹的基礎還不夠,要加油了;
下面是我的AC代碼。

#include<stdio.h> #include<string.h> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 #define mid int m = (l + r)>>1 #define maxn 200000 int sum[maxn<<2],pos[maxn],val[maxn],ans[maxn<<2];//ans儲存插入的值; void push_up(int rt) { sum [rt] = sum[rt<<1]+sum[rt<<1|1]; } void build(int l, int r, int rt) { sum[rt]=r-l+1; if(l == r)return; mid; build(lson); build(rson); } void update(int pos, int val, int l, int r, int rt) { if(l == r){ans[rt]=val;sum[rt]--;return;} mid; if(pos <= sum[rt<<1])update(pos, val, lson); //根據左右兒子空位的多少和插入數據的位置比較來確定插入哪個兒子 else update(pos -sum[rt<<1], val, rson); push_up(rt); } void print(int l, int r, int rt) { if(l == r){printf("%d ",ans[rt]);return;} mid; print(lson); print(rson); } int main() { int n,i; while(~scanf("%d",&n)) { for(i=0;i<n;i++) scanf("%d%d",&pos[i],&val[i]); build(1, n ,1); for(i=n-1;i>=0;i--) update(pos[i]+1, val[i], 1, n, 1); print(1, n, 1); printf("\n"); } return 0; }
還有一種是節點記錄已占有的位置(即非空位),cnt[rt]+pos<=m訪問左節點,否則就訪問右兒子(訪問右兒子時節點修改為cnt[rt]+pos);

#include<stdio.h> #include<string.h> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 #define mid int m = (l + r)>>1 #define maxn 200000 int cnt[maxn<<2],ans[maxn<<2],pos[maxn],val[maxn]; void update(int pos, int val, int l, int r, int rt) { cnt[rt]++; if(l == r){ans[rt]=val;return;} mid; if(pos + cnt[rt<<1] <= m)update(pos, val, lson); else update(pos+cnt[rt<<1], val, rson); } void print(int l, int r, int rt) { if(l == r){printf("%d ",ans[rt]);return;} mid; print(lson); print(rson); } int main() { int n,i; while(~scanf("%d",&n)) { memset(cnt,0,sizeof(cnt)); for(i=0;i<n;i++) scanf("%d%d",&pos[i],&val[i]); for(i=n-1;i>=0;i--) { update(pos[i]+1, val[i], 1, n, 1); } print(1, n, 1); printf("\n"); } return 0; }