Description
Solution
转化题意
坐标为偶数保证了不会停留在坐标轴上
首先可以发现两维坐标是独立的
那么分开考虑,令S为坐标前缀和
那么第i操作后能造成伤害的条件是
S[i]∗S[i−1]<0
,也可以写成
min(S[i],S[i−1])<0<max(S[i],S[i−1])
既然题目是指针左移右移,那么这肯定是有用的
设一个变量Tag表示当前指针到右端点的数都加上了tag
考虑在修改的时候维护答案。
设w为当前指针位置
不妨计算答案的增量,很明显就是w与w-1造成的贡献与[w,n]这段的贡献
我们要统计有多少
i>w,min(S[i],S[i−1])<0<max(S[i],S[i−1])
可以简单的在线段树上区间加,查询0点实现
S都加上了tag,相当于0点左移tag
答案就变成
min(S[i],S[i−1])<−tag<max(S[i],S[i−1])
这次修改又加上了delta
那么就是
min(S[i],S[i−1])<−tag−delta<max(S[i],S[i−1])
线段树单点查询,加上delta的减去不加的就是增量
对于一次右移,我们需要满足指针左边的都是实际值,那么S[w]+=tag,w++,然后线段树中删去这个w和w-1的贡献
对于一次左移,我们需要满足指针右边的都是加上tag以后的值,那么w–,S[w]-=tag,然后线段树中加上w和w+1的贡献
注意线段树的时候c++负数整除实际上是绝对值下取整,要特判
Code
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 100005
#define M 3000005
#define R 50000005
using namespace std;
int a[N][2],n,m,w,t[M][2],s1[M],lz[M],ans,tag1,tag2,sx[N],sy[N],n1;
void down(int k)
{
s1[t[k][0]]+=lz[k],s1[t[k][1]]+=lz[k];
lz[t[k][0]]+=lz[k],lz[t[k][1]]+=lz[k];
lz[k]=0;
}
void ins(int k,int l,int r,int x,int y,int v)
{
x=max(x,l),y=min(y,r);
if(x>y||!k) return;
if(l==x&&r==y) s1[k]+=v,lz[k]+=v;
else
{
int mid=(l+r)/2;
if(l+r<0) mid+=(l+r)%2;
if(!t[k][0]) t[k][0]=++n1,t[k][1]=++n1;
down(k);
ins(t[k][0],l,mid,x,y,v),ins(t[k][1],mid+1,r,x,y,v);
}
}
int get(int k,int l,int r,int x)
{
if(l==r&&x==l) return s1[k];
int mid=(l+r)/2;
if(l+r<0) mid+=(l+r)%2;
if(!t[k][0]) t[k][0]=++n1,t[k][1]=++n1;
down(k);
if(x<=mid) return get(t[k][0],l,mid,x);
else return get(t[k][1],mid+1,r,x);
}
int main()
{
cin>>n;
fo(i,1,n) scanf("%d%d",&a[i][0],&a[i][1]);
cin>>m;
w=1;
sx[0]=sy[0]=1;
n1=2;
fo(i,1,n)
{
sx[i]=sx[i-1]+a[i][0],sy[i]=sy[i-1]+a[i][1];
if(i>1) ins(1,-R,R,min(sx[i],sx[i-1]),max(sx[i],sx[i-1]),1);
if(i>1) ins(2,-R,R,min(sy[i],sy[i-1]),max(sy[i],sy[i-1]),1);
}
ans=get(1,-R,R,0)+get(2,-R,R,0)+(sx[1]<0)+(sy[1]<0);
tag1=tag2=0;
fo(i,1,m)
{
char ch;
scanf("\n%c",&ch);
if(ch=='B')
{
if(w!=1)
{
sx[w-1]-=tag1,sy[w-1]-=tag2;
ins(1,-R,R,min(sx[w],sx[w-1]),max(sx[w],sx[w-1]),1);
ins(2,-R,R,min(sy[w],sy[w-1]),max(sy[w],sy[w-1]),1);
w--;
}
}
if(ch=='F')
{
if(w!=n)
{
ins(1,-R,R,min(sx[w],sx[w+1]),max(sx[w],sx[w+1]),-1);
ins(2,-R,R,min(sy[w],sy[w+1]),max(sy[w],sy[w+1]),-1);
sx[w]+=tag1,sy[w]+=tag2;
w++;
}
}
if(ch=='C')
{
int x,y,vl1,vl2;
scanf("%d%d",&x,&y);
vl1=x-a[w][0],vl2=y-a[w][1];
a[w][0]=x,a[w][1]=y;
ans+=(get(1,-R,R,-tag1-vl1)-get(1,-R,R,-tag1)+get(2,-R,R,-tag2-vl2)-get(2,-R,R,-tag2));
ans+=((sx[w]+vl1+tag1)*sx[w-1]<0)-((sx[w]+tag1)*sx[w-1]<0)+((sy[w]+vl2+tag2)*sy[w-1]<0)-((sy[w]+tag2)*sy[w-1]<0);
tag1+=vl1,tag2+=vl2;
}
if(ch=='Q')
{
printf("%d\n",ans);
}
}
}