1. 程式人生 > >bzoj2957樓房重建

bzoj2957樓房重建

d+ fin com href col pre target blank string

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=2957

線段樹。每個點記錄斜率,要一個單增的序列長度(從1開始)。

線段樹每個點記錄自己區間的max和單增長度,pushup的時候通過mx [ ls ]判斷往哪個兒子遞歸。

需要註意的是當右兒子的長度全部可以加上是,不能加s [ rs ],因為不一定全在總的單增序列上(只有rs中大於mx[ls]的那一部分);

  所以右兒子的貢獻應該是原先總區間的s減去左兒子的s,因為單增序列從最左端開始,總序列中左兒子肯定全在。

#include<iostream>
#include<cstdio>
#include
<cstring> #define ll long long using namespace std; const int N=1e5+5; int n,m,x,s[N<<2]; double z,mx[N<<2]; int dg(int cur,double lm,int l,int r) { if(l==r)return mx[cur]>lm; int ls=(cur<<1),rs=(cur<<1|1); if(mx[ls]<=lm)return dg(rs,lm,((l+r)>>1
)+1,r); return dg(ls,lm,l,((l+r)>>1))+s[cur]-s[ls]; } void pushup(int bh,int l,int r) { int ls=(bh<<1),rs=(bh<<1|1); mx[bh]=mx[ls];s[bh]=s[ls]; if(mx[rs]<=mx[ls])return; mx[bh]=mx[rs]; // printf(" ()l=%d r=%d mx=%lf\n",l,r,mx[bh]); s[bh]+=dg(rs,mx[ls],((l+r)>>1
)+1,r); } void add(int bh,int l,int r) { int mid=((l+r)>>1); if(l==r){ mx[bh]=z;s[bh]=1;//bh,不是l // printf("l=%d r=%d mx=%lf s=%d\n",l,r,mx[bh],s[bh]); return; } if(x<=mid)add(bh<<1,l,mid); else add(bh<<1|1,mid+1,r); pushup(bh,l,r); // printf("l=%d r=%d mx=%lf s=%d\n",l,r,mx[bh],s[bh]); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%lf",&x,&z);z/=x; add(1,1,n); printf("%d\n",s[1]); } return 0; }

bzoj2957樓房重建