一句話題意,一條數軸上有若干樓房,座標為\(xi\)的樓房有高度\(hi\),那麼它的斜率為\(hi/xi\),操作包含單元素高度修改,動態詢問最長上公升斜率序列個數
一開始想什麼分治或是離線操作之類的,卻因為水平低並不會做,看了題解居然發現就是線段樹!看了一下感覺真妙啊,線段樹真是個神奇的資料結構
線段樹維護兩個東西\(sum[now],mx[now]\);
\(sum[now]\)是\(now\)管轄區間\([l,r]\)的最長上公升斜率個數
類似的\(mx[now]\)就是那個區間最大斜率,也就是最長上公升序列中最右邊的
我們假設更新操作遞迴到\([l,r]\)區間,設\(p\)為\([l,mid]\)區間最大斜率
\(mx[now<<1]\)
那麼\([l,r]\)區間的貢獻\((sum[now])\)顯然等於\([l,mid]\)區間貢獻\((sum[now<<1])\)
\(+\) 統計\([mid+1,r]\)區間中大於\(p\)的最長上公升序列個數.
那麼怎麼計算\([mid+1,r]\)區間中的大於\(p\)的最長上公升序列個數呢,這個我在**中給出了詳細的注釋
#include #include #include #include #include #include #define ll long long
#define ri register int
using std::min;
using std::max;
template inline void read(t &x)
const int maxn=100005;
const int inf=0x7fffffff;
int n,m,t;
double dta,p;
struct segment_tree
void update(int now,int l,int r)
int mid=(l+r)>>1;
if(t<=mid)update(now<<1,l,mid);
else update(now<<1|1,mid+1,r);
mx[now]=max(mx[now<<1],mx[now<<1|1]);
p=mx[now<<1];//左區間最大值
sum[now]=sum[now<<1]+calc(now<<1|1,mid+1,r);//計算右區間貢獻
return ;
}}t;
int main()
return 0;
}
P4198 樓房重建
傳送門 很妙的思路 首先,我們可以把每一棟樓房轉化為它的頂部到原點這條直線的斜率,這樣就變成了從乙個序列中選出乙個最長上公升子串行 其實不是最長上公升子串行,不過可以這麼理解 考慮用線段樹來維護,對於每個區間,我們維護這個區間的最大值以及這個區間的答案,那麼最後的答案就是 ans 1 對於葉節點來說...
P4198 樓房重建
題意 n 棟待建的樓房,站在 0,0 點,對於樓房 i 來說,如果從原點能看到樓房的樓頂且沒有樓房阻擋,就算能看到該樓房 每次對於一座樓房可以增加高度和減小高度,每次修改後問最多能看到多少棟樓房?題解 線段樹維護區間斜率最大值,以及區間最長上公升子串行 即斜率遞增 的長度,難點在於區間的合併 對於每...
P4198 樓房重建(思維)
題目描述小 a 的樓房外有一大片施工工地,工地上有 n 棟待建的樓房。每天,這片工地上的房子拆了又建 建了又拆。他經常無聊地看著窗外發呆,數自己能夠看到多少棟房子。為了簡化問題,我們考慮這些事件發生在乙個二維平面上。小 a 在平面上 0,0 點的位置,第 i 棟樓房可以用一條連線 i,0 和 i,h...