小a的樓房外有一大片施工工地,工地上有n棟待建的樓房。每天,這片工地上的房子拆了又建、建了又拆。他經常無聊地看著窗外發呆,數自己能夠看到多少棟房子。
為了簡化問題,我們考慮這些事件發生在乙個二維平面上。小a在平面上(0,0)點的位置,第i棟樓房可以用一條連線(i,0)和(i,hi)的線段表示,其中hi為第i棟樓房的高度。如果這棟樓房上任何乙個高度大於0的點與(0,0)的連線沒有與之前的線段相交,那麼這棟樓房就被認為是可見的。
施工隊的建造總共進行了m天。初始時,所有樓房都還沒有開始建造,它們的高度均為0。在第i天,建築隊將會將橫座標為xi的房屋的高度變為yi(高度可以比原來大---修建,也可以比原來小---拆除,甚至可以保持不變---建築隊這天什麼事也沒做)。請你幫小a數數每天在建築隊完工之後,他能看到多少棟樓房?
第一行兩個正整數n,m
接下來m行,每行兩個正整數xi,yi
m行,第i行乙個整數表示第i天過後小a能看到的樓房有多少棟
3 42 43 6
1 1000000000
1 1111
2資料約定
對於所有的資料1<=xi<=n,1<=yi<=10^9
n,m<=100000
設len為乙個區間不考慮其他區間所帶來的影響時的最長上公升序列的長度,ans為y對答案的影響
那麼我們需要的就是將兩個區間的值合併 如圖
首先,x->len是可以直接作為答案的一部分的.
當x->max > y->lch->max 時,y->lch不會產生任何貢獻,所以ans=rch的貢獻
當x->max < y->lch->max 時,x不會對y->rch產生任何影響,所以ans=lch的貢獻+y->len - y->lch->len(注意不是y->rch->len因為lch對rch還可能有影響)
這樣遞迴下去即可 **
#include #define maxn 100005
inline void read(int& x)
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
x*=y;
}templateinline t m_max(t x,t y)
int n,m;
struct tree
inline int find(tree* x,double v)
inline void mt()
inline void build(int x,int y,tree*& now)
inline void update(int x,double v,tree*& now)
int mid=now->lc+now->rc>>1;
if(x<=mid) update(x,v,now->lch);
else update(x,v,now->rch);
now->mt();
} void* operator new(size_t size);
}*root,*__head,*__tail;
void* tree::operator new(size_t size)
int main()
return 0;
}
BZOJ2957 樓房重建(線段樹)
這裡放傳送門 可以發現如果一段樓房能被看見,那麼它們跟原點的連線的斜率都是單調遞增的。於是這就變成了乙個維護上公升序列的題。這裡的上公升序列不是最長上公升子串行那樣的東西,而是相當於貪心地選擇,選中的子串行中的每乙個元素它前面都不能存在大於等於它的元素。比如說,有乙個斜率序列是1,2,4,3,4,如...
BZOJ2957 樓房重建 線段樹
題目 time limit 10 sec memory limit 256 mb submit 2259 solved 1069 submit status discuss 小a的樓房外有一大片施工工地,工地上有n棟待建的樓房。每天,這片工地上的房子拆了又建 建了又拆。他經常無聊地看著窗外發呆,數自...
線段樹 bzoj2957 樓房重建
大概意思就是求序列從一位置開始的動態上公升序列。分塊可過,但這一類題目其實可用線段樹。也就是維護每個區間的上公升序列長度。下面這種求法只是用於當前節點所覆蓋的區間完全被查詢區間覆蓋。具體而言,查詢時如果左兒子的max值 k,只去右兒子找。如果max lc k,那麼右兒子的長度全部符合,只要再遞迴著找...