【線段樹】[Luogu P4198]樓房修建

顯然要維護斜率區間單調遞增c++

而且第一個必選,後一個比前一個選中的斜率大的必選git

考慮如何合併兩個區間spa

咱們維護一個least值,least這個值必選,且以後選的都必須嚴格大於least,Push_Up的時候就像在線段樹上二分同樣作就行了
code

這樣每次Push_Up是$logn$的,線段樹單點修改時$logn$的,因此總複雜度是$O(nlog^2n)$的,再維護一個區間最大值能夠作到一些沒必要要可是能夠卡常的剪枝...blog

 

 

 1 #include<bits/stdc++.h>
 2 #define writeln(x)  write(x),puts("")
 3 #define writep(x)   write(x),putchar(' ')
 4 using namespace std;
 5 inline int read(){
 6     int ans=0,f=1;char chr=getchar();
 7     while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();}
 8     while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();}
 9     return ans*f;
10 }void write(int x){
11     if(x<0) putchar('-'),x=-x;
12     if(x>9) write(x/10);
13     putchar(x%10+'0');
14 }const int M = 2e5+5;
15 int s[M<<2],n,T;
16 double mx[M<<2],a[M];
17 #define ls (i<<1)
18 #define rs (i<<1|1)
19 #define mid (l+r>>1)
20 inline int Push(int i,int l,int r,double least){
21     if(mx[i]<=least) return 0;
22     if(a[l]>least) return s[i];
23     if(l==r) return a[l]>least;
24     if(mx[ls]<=least) return Push(rs,mid+1,r,least);
25     return Push(ls,l,mid,least)+s[i]-s[ls];
26 }inline void Push_Up(int i,int l,int r){
27     mx[i]=max(mx[ls],mx[rs]);
28     s[i]=s[ls]+Push(rs,mid+1,r,mx[ls]);
29 }void Update(int i,int l,int r,int pos,double x){
30     if(l==r)return mx[i]=x,s[i]=1,void();
31     if(pos<=mid) Update(ls,l,mid,pos,x);
32     else Update(rs,mid+1,r,pos,x);
33     Push_Up(i,l,r);
34 }int main(){
35     n=read(),T=read();
36     while(T--){
37         int x=read(),y=read();
38         a[x]=y*1.0/(x*1.0);
39         Update(1,1,n,x,y*1.0/(1.0*x));
40         printf("%d\n",s[1]);
41     }return 0;
42 }
相關文章
相關標籤/搜索