1. 程式人生 > >[數據結構]bzoj2957樓房重建

[數據結構]bzoj2957樓房重建

ret 數據 不變 原本 truct 一行 max 大小 etc

Description

  小A的樓房外有一大片施工工地,工地上有N棟待建的樓房。每天,這片工地上的房子拆了又建、建了又拆。他經常無聊地看著窗外發呆,數自己能夠看到多少棟房子。
  為了簡化問題,我們考慮這些事件發生在一個二維平面上。小A在平面上(0,0)點的位置,第i棟樓房可以用一條連接(i,0)和(i,Hi)的線段表示,其中Hi為第i棟樓房的高度。如果這棟樓房上任何一個高度大於0的點與(0,0)的連線沒有與之前的線段相交,那麽這棟樓房就被認為是可見的。
  施工隊的建造總共進行了M天。初始時,所有樓房都還沒有開始建造,它們的高度均為0。在第i天,建築隊將會將橫坐標為Xi的房屋的高度變為Yi(高度可以比原來大---修建,也可以比原來小---拆除,甚至可以保持不變---建築隊這天什麽事也沒做)。請你幫小A數數每天在建築隊完工之後,他能看到多少棟樓房?

Input

  第一行兩個正整數N,M
  接下來M行,每行兩個正整數Xi,Yi

Output


  M行,第i行一個整數表示第i天過後小A能看到的樓房有多少棟

Sample Input


3 4
2 4
3 6
1 1000000000
1 1

Sample Output


1
1
1
2
數據約定
  對於所有的數據1<=Xi<=N,1<=Yi<=10^9,N,M<=100000
=========華麗麗的分割線============ 雖然是一個清華集訓的題目,不過還是可做的嘛。。。 一開始的時候自己寫了一個程序,然後怎麽都沒有調出來。 考慮本題,給出一個數列,然後要求支持單點修改以及詢問比自己左邊所有數都大的數就幾個。
考慮線段樹,維護出一段中的高度最大值以及別的數都不考慮的情況下(這個一定不能漏)比這樣的數有幾個。 考慮合並兩個線段,高度的最大值是很容易合並的,直接取一個max就可以了。 對於貢獻度,我們發現一個線段的左半部分所有滿足的數在原來的線段中一定滿足,於是我們只需要考慮右半部分。 我們寫一個函數calc(node,k)表示node這個線段在左側有一個大小為k的數的時候內部滿足條件的數的個數。 於是發現如果這個線段的左半部分的最大值小於等於k,那麽左半部分貢獻就是0,直接返回calc(node*2+1,k), 如果左半部分最大值大於k,那麽右半部分原本的個數是不會變的,然後再加上calc(node*2,k)就可以了,
時間復雜度O(nlog^2n), 聽說這題卡精度,在呂爺爺的幫助下我學會了fraction,
 1 #include <bits/stdc++.h>
 2 #define Maxn 100007
 3 using namespace std;
 4 int read()
 5 {
 6     int x=0,f=1;char ch=getchar();
 7     while (ch<0||ch>9){if (ch==-) f=-1;ch=getchar();}
 8     while (ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
 9     return x*f;
10 }
11 struct fraction
12 {
13     int dx,dy;
14 };
15 bool operator >(fraction a, fraction b)
16 {
17     return (1LL*a.dx*b.dy>1LL*a.dy*b.dx);
18 }
19 bool operator >=(fraction a, fraction b)
20 {
21     return (1LL*a.dx*b.dy>=1LL*a.dy*b.dx);
22 }
23 bool operator <(fraction a, fraction b)
24 {
25     return (1LL*a.dx*b.dy<1LL*a.dy*b.dx);
26 }
27 bool operator <=(fraction a, fraction b)
28 {
29     return (1LL*a.dx*b.dy<=1LL*a.dy*b.dx);
30 }
31 int n,m;
32 struct seg
33 {
34     int lx,rx,cnt;
35     fraction hmax;
36 };
37 seg tree[Maxn*4];
38 void build(int node, int l, int r)
39 {
40     tree[node].lx=l,tree[node].rx=r,tree[node].cnt=0;
41     tree[node].hmax=(fraction){0,1};
42     if (tree[node].lx==tree[node].rx) return;
43     int mid=(l+r)/2;
44     build(node*2,l,mid),build(node*2+1,mid+1,r);
45 }
46 int calc(int node, fraction h)
47 {
48     if (tree[node].hmax<=h) return 0;
49     if (tree[node].lx==tree[node].rx) return 1;
50     if (tree[node*2].hmax<=h) return calc(node*2+1,h);
51     else return tree[node].cnt-tree[node*2].cnt+calc(node*2,h);
52 }
53 void update(int node, int pos, fraction h)
54 {
55     if (tree[node].rx<pos) return;
56     if (tree[node].lx>pos) return;
57     if (tree[node].lx==tree[node].rx)
58     {
59         tree[node].hmax=h;
60         tree[node].cnt=1;
61         return;
62     }
63     update(node*2,pos,h),update(node*2+1,pos,h);
64     tree[node].hmax=max(tree[node*2].hmax,tree[node*2+1].hmax);
65     tree[node].cnt=tree[node*2].cnt+calc(node*2+1,tree[node*2].hmax);
66 }
67 int main()
68 {
69     n=read(),m=read();
70     build(1,1,n);
71     while (m--)
72     {
73         int x=read(),y=read();
74         update(1,x,(fraction){y,x});
75         printf("%d\n",tree[1].cnt);
76     }
77     return 0;
78 }

代碼如下:

[數據結構]bzoj2957樓房重建