线段树的高级操作
首先肯定将每个点化成斜率来算
我们考虑在线段树的每个节点记录一个sum[k],表示如果当前只有这个节点范围内的那些楼房,完全不考虑这个区间之外的楼房,能看到多少个楼房
那么显然在单点更新的时候,更新的是线段树上一条链上的节点,那么没有被更新到的节点sum值是不会变的,所以每次更新只会有logn个sum被更新
考虑如果sum[k]的孩子的sum都已经计算好了,该如何更新sum[k]的值
首先,sum[k]显然应该包含sum[k<<1]的那些点,他们都应该被加进答案
定义函数calc(premax,cur)表示如果之间出现的最大的数是premax的话,我在cur这个区间内能看到多少个点
则sum[k]=sum[k<<1]+calc(max[k<<1],k<<1|1)
记k<<1|1为rson,我们考虑将rson再细分,考虑rson<<1和rson<<1|1,记k<<1区间的最大值为max1,rson<<1区间的最大值为max2
如果max1>=max2,那么rson<<1里面的点会被k<<1中的最大值全部挡住,所以rson<<1中的点都不会被计入答案,此时calc(max[k<<1],rson)=calc(max[k<<1],rson<<1|1)
如果max1<max2,那么calc(max[k<<1],rson)=calc(max[k<<1].rson<<1)+calc(max[rson<<1],rson<<1|1)
但是注意我们当前在计算sum[k],那么他的孩子们都已经被计算完了,所以后面的calc(maxn[rson<<1],rson<<1|1)实际上是不用利用函数算的,可以直接写成sum[rson]-sum[rson<<1],注意千万不能写成sum[rson<<1|1],因为单独算rson<<1|1的sum没有考虑到max[rson<<1]对答案的限制作用
所以max1<max2时,calc(max[k<<1],rson)=sum[rson]-sum[rson<<1]+calc(max[k<<1],rson<<1)
可以看到calc函数每次向孩子走,所以会在logn的时间内算出,calc函数在一次更新中被调用了logn次,所总复杂度为O(nlog2n)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,LL>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;
const int MOD=100003;
const LL LINF=2e16;
const int INF=2e9;
const int magic=348;
const double eps=1e-10;
inline int getint()
{
char ch;int res;bool f;
while (!isdigit(ch=getchar()) && ch!='-') {}
if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
while (isdigit(ch=getchar())) res=res*10+ch-'0';
return f?res:-res;
}
struct node
{
int left,right;
double maxn;int sum;
}tree[600048];
int n,q;
inline void build(int cur,int left,int right)
{
tree[cur].left=left;tree[cur].right=right;
tree[cur].maxn=-1;tree[cur].sum=0;
if (left!=right)
{
int mid=(left+right)>>1;
build(cur<<1,left,mid);
build(cur<<1|1,mid+1,right);
}
}
inline int calc(double cmp,int cur)
{
if (tree[cur].left==tree[cur].right) return tree[cur].maxn>cmp?1:0;
if (tree[cur<<1].maxn<=cmp)
return calc(cmp,cur<<1|1);
else
return tree[cur].sum-tree[cur<<1].sum+calc(cmp,cur<<1);
}
inline void update(int cur,int pos,double newval)
{
if (tree[cur].left==tree[cur].right)
{
tree[cur].maxn=newval;
tree[cur].sum=1;
return;
}
int mid=(tree[cur].left+tree[cur].right)>>1;
if (pos<=mid) update(cur<<1,pos,newval); else update(cur<<1|1,pos,newval);
tree[cur].maxn=max(tree[cur<<1].maxn,tree[cur<<1|1].maxn);
tree[cur].sum=tree[cur<<1].sum+calc(tree[cur<<1].maxn,cur<<1|1);
}
int main ()
{
int pos,height;double val;
n=getint();q=getint();
build(1,1,n);
while (q--)
{
pos=getint();height=getint();
val=double(height)/double(pos);
update(1,pos,val);
printf("%d\n",tree[1].sum);
}
return 0;
}