題意:給n個目標線段,在(x,0)處開始沿y軸射擊目標,最多能擊中前k個,問k個目標距離和。
前幾天學了下主席樹,然後又發現多校裡面正好有這類題,所以就來做一下。
一開始自己的想法是這樣的:以線段的橫座標來建立函式式線段樹,但是各種tle,re,wa,最後實在傷不起了,這裡解釋下為什麼會tle和re,因為如果這樣建線段樹,那麼每次放入一條線段就要成段更新,影響的結點數比較多,所以需要很大的空間,然後查詢時又要遍歷較多的節點,所以導致超時,超記憶體。但是我也看到有人用這種方法過的,但是記憶體卡的非常死,如果用結構體寫線段樹,會超記憶體。
題解的思路:首先按距離x軸的距離建立函式式線段樹(需要離散化),然後依次將線段的2*n個端點插入到線段樹中,左端點+1,右端點+1(實際上是r+1的位置
),表示在[l,r]區間內有一條線段,個人覺得這裡用的很巧妙。然後查詢每個x時,用二分法找到該線段樹中的位置,然後再這棵線段樹上找前k個就可以了。
**如下:
#include#include#include#include#include#include#include#include#include#include#include#define n 100005
#define ll __int64
#define inf 0x77ffffff
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
int dist[n];
struct node
}dot[2*n];
struct node1
tree[50*n];
int rt[2*n],cur;
int build(int l,int r)
int update(int o,int l,int r,int pos,int v,int val)
int m = (l+r)/2;
if(pos <= m) tree[k].l = update(tree[o].l,l,m,pos,v,val);
else tree[k].r = update(tree[o].r,m+1,r,pos,v,val);
tree[k].num = tree[tree[k].l].num + tree[tree[k].r].num;
tree[k].val = tree[tree[k].l].val + tree[tree[k].r].val;
return k;
}ll query(int o,int l,int r,int k)
int m = (l+r)/2;
if(k <= tree[tree[o].l].num) return query(tree[o].l,l,m,k);
else return tree[tree[o].l].val + query(tree[o].r,m+1,r,k-tree[tree[o].l].num);
}int main()
sort(dist,dist+n);
int tot = unique(dist,dist+n) - dist;//range:1--tot
sort(dot,dot+2*n);
cur = 0;
rt[0] = build(1,tot);
for(i = 0; i < 2*n; i++)
ll pre = 1;
while(m--)
if(pre > p) ans = 2*ans;
printf("%i64d\n",ans);
pre = ans;}}
return 0;
}
HDU 4866 多校1 主席樹 掃瞄線
終於是解決了這個題目了 不過不知道下一次碰到主席樹到底做不做的出來,這個東西稍微難一點就不一定能做得出 離散化 掃瞄線式的建樹,所以對於某個座標二分找到對應的那顆主席樹,即搜尋出結果即可 因為是掃瞄線式的建樹,找到對應的樹之後,就知道該點上面的線段有多少條了 其他就是普通主席樹的操作了 主席樹裡面維...
可持久化線段樹 HDU4866 Shooting
題目鏈結 一些平行於x軸的線段作為射擊目標,每次在x軸上選乙個點向y軸方向射擊,可以射中最近的k個目標,得分是射中目標的高度和,求這個得分。對高度建立函式式線段樹,按順序對x軸座標建樹,維護區間和和區間個數,每次射擊詢問該線段樹即可。include include include include i...
tyvj4866 擺攤 線段樹MEX
真的感覺自己real弱啊 在zhx的 幫助下理解了這個內容 我不知道自己這麼低的智商未來會不會有出路 有一些必要的解釋,放在了程式中 next i 0 表示 在序列a中下標為i 1到m中最近一次出現a i 1的位置 關於這個線段樹的使用 線段樹其實我們是查詢截至到右端點,我們現在可用的最小值 我每次...