这个题的线段树倒还没有特别难,只是想到如何去用这个线段树比较麻烦。这里我们动态地想象这整个过程,当竖线在最左边时,对于某个横线,大于线的纵坐标,就是第一象限,就是st的得分;小于这个纵坐标,就是第四象限,就是ol的得分。我们把每个点的这两个值都用线段树记下来。然后,处理这个竖线上的点。当我们把竖线朝右移的时候,一个原竖线上的点,对于高于它的点,将变成第三象限的点,我们更新记录高于它的点的st的得分。而对于低于它的点,我们更新ol的得分。这样,我们把可能的竖线都处理完,所有的点就都被遍历了一遍。
平生第二次手写线段树,果不其然写错了哩。照着人家的题解改了一遍才过。
struct segment_tree{
int x,y;
void pushdown(int rt)
{
tree[rt*2].flag[0]+=tree[rt].flag[0];
tree[rt*2+1].flag[0]+=tree[rt].flag[0];
tree[rt*2].flag[1]+=tree[rt].flag[1];
tree[rt*2+1].flag[1]+=tree[rt].flag[1];
tree[rt].flag[0]=0; tree[rt].flag[1]=0;
return;
}
void build(int l,int r,int rt)
{
//cout<<"l="<<l<<" r="<<r<<" rt="<<rt<<endl;
tree[rt].flag[0]=0;
tree[rt].flag[1]=0;
if (l==r)
{
tree[rt].flag[0]=st[l];
tree[rt].flag[1]=ol[l];
return;
}
int mid=l+r>>1;
build(l,mid,rt*2);
build(mid+1,r,rt*2+1);
return;
}
void update(int l,int r,int rt,int type,int d)
{
//cout<<"l="<<l<<" r="<<r<<" x="<<x<<" y="<<y<<endl;
if (l>=x && r<=y)
{
tree[rt].flag[type]+=d;
return;
}
pushdown(rt);
int mid=l+r>>1;
if (mid>=x)
{
update(l,mid,rt*2,type,d);
}
if (mid<y)
{
update(mid+1,r,rt*2+1,type,d);
}
}
void query(int l,int r,int &mi, int &mx, int rt,int pos)
{
if (l==r)
{
mi=tree[rt].flag[0];
mx=tree[rt].flag[1];
return;
}
pushdown(rt);
int mid=l+r>>1;
if (pos<=mid) query(l,mid,mi,mx,rt*2,pos);
else query(mid+1,r,mi,mx,rt*2+1,pos);
}
};