题目描述
https://www.loj.ac/problem/503
题解
x和y是可以分开考虑的。
设si表示某维坐标的前缀和。
要求统计多少i满足si*si-1<=0(此时会有正负交替)。
我们发现这个条件等价于max(si,si-1)>=0且min(si,si-1)<=0。
这样两个限制依然不好统计。
改成用n减去不满足条件的。
1、max(si,si-1)<=0
2、min(si,si-1)>=0
这两个条件互不相交。
用线段树维护s,用平衡树保留指针之后的max(si,si-1)或min(si,si-1)。
这样每次修改就可以在平衡树中统计贡献,同时在线段树上修改。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000+10;
int ad[maxn*4],a[maxn][2],s[maxn],b[maxn];
int tree[maxn][2],father[maxn],key[maxn],size[maxn],da[maxn];
int ask[maxn*3][3],ans[maxn*3],sta[maxn];
int i,j,k,l,t,n,m,root,tot,top,now;
char ch;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
char get(){
char ch=getchar();
while (ch!='B'&&ch!='F'&&ch!='C'&&ch!='Q') ch=getchar();
return ch;
}
void mark(int p,int v){
ad[p]+=v;
}
void down(int p){
if (ad[p]){
mark(p*2,ad[p]);
mark(p*2+1,ad[p]);
ad[p]=0;
}
}
void change(int p,int l,int r,int a,int b,int v){
if (l==a&&r==b){
mark(p,v);
return;
}
down(p);
int mid=(l+r)/2;
if (b<=mid) change(p*2,l,mid,a,b,v);
else if (a>mid) change(p*2+1,mid+1,r,a,b,v);
else change(p*2,l,mid,a,mid,v),change(p*2+1,mid+1,r,mid+1,b,v);
}
int query(int p,int l,int r,int a){
if (!a) return 1;
if (l==r) return ad[p]+s[l];
down(p);
int mid=(l+r)/2;
if (a<=mid) return query(p*2,l,mid,a);else return query(p*2+1,mid+1,r,a);
}
int pd(int x){
return tree[father[x]][1]==x;
}
void update(int x){
size[x]=size[tree[x][0]]+size[tree[x][1]]+1;
}
void rotate(int x){
int y=father[x],z=pd(x);
father[x]=father[y];
if (father[y]) tree[father[y]][pd(y)]=x;
tree[y][z]=tree[x][1-z];
if (tree[x][1-z]) father[tree[x][1-z]]=y;
tree[x][1-z]=y;
father[y]=x;
if (root==y) root=x;
update(y);
update(x);
}
void mark2(int x,int v){
da[x]+=v;
}
void clear(int x){
if (!x) return;
if (da[x]){
key[x]+=da[x];
mark2(tree[x][0],da[x]);
mark2(tree[x][1],da[x]);
da[x]=0;
}
}
void remove(int x,int y){
top=0;
while (x!=y){
sta[++top]=x;
x=father[x];
}
while (top) clear(sta[top--]);
}
void splay(int x,int y){
remove(x,y);
while (father[x]!=y){
if (father[father[x]]!=y)
if (pd(father[x])==pd(x)) rotate(father[x]);else rotate(x);
rotate(x);
}
}
void insert(int &x,int y){
if (!x){
x=y;
size[x]=1;
return;
}
clear(x);
if (key[y]<=key[x]){
insert(tree[x][0],y);
father[tree[x][0]]=x;
}
else{
insert(tree[x][1],y);
father[tree[x][1]]=x;
}
update(x);
}
int find(int x){
if (!x) return 0;
clear(x);
if (key[x]<=0) return find(tree[x][1])+size[tree[x][0]]+1;
else return find(tree[x][0]);
}
int find2(int x){
if (!x) return 0;
clear(x);
if (key[x]>=0) return find2(tree[x][0])+size[tree[x][1]]+1;
else return find2(tree[x][1]);
}
int merge(int a,int b){
if (!a||!b) return a+b;
int t=a;
while (tree[t][1]) t=tree[t][1];
splay(t,0);
tree[t][1]=b;
father[b]=t;
update(t);
return t;
}
void work(int p){
s[0]=a[0][p];
fo(i,1,n) s[i]=s[i-1]+a[i][p];
fo(i,1,n) da[i]=0;
root=now=0;
fo(i,1,n){
key[i]=max(s[i],s[i-1]);
father[i]=tree[i][0]=tree[i][1]=0;
if (key[i]<=0) now++;
insert(root,i);
splay(i,0);
}
fo(i,1,4*n) ad[i]=0;
j=1;
fo(i,1,m){
if (ask[i][0]==0&&j>1){
j--;
key[j]=max(query(1,1,n,j),query(1,1,n,j-1));
father[j]=tree[j][0]=tree[j][1]=0;
insert(root,j);
splay(j,0);
}
else if (ask[i][0]==1&&j<n){
splay(j,0);
clear(j);
father[tree[j][0]]=father[tree[j][1]]=0;
root=merge(tree[j][0],tree[j][1]);
j++;
}
else if (ask[i][0]==3){
now-=find(root);
t=ask[i][p+1]-(query(1,1,n,j)-query(1,1,n,j-1));
splay(j,0);
clear(j);
father[tree[j][0]]=father[tree[j][1]]=0;
root=merge(tree[j][0],tree[j][1]);
mark2(root,t);
change(1,1,n,j,n,t);
key[j]=max(query(1,1,n,j),query(1,1,n,j-1));
father[j]=tree[j][0]=tree[j][1]=0;
insert(root,j);
splay(j,0);
now+=find(root);
}
else if (ask[i][0]==2) ans[ask[i][1]]-=now;
}
fo(i,1,n) da[i]=0;
root=now=0;
fo(i,1,n){
key[i]=min(s[i],s[i-1]);
father[i]=tree[i][0]=tree[i][1]=0;
if (key[i]>=0) now++;
insert(root,i);
splay(i,0);
}
fo(i,1,4*n) ad[i]=0;
j=1;
fo(i,1,m){
if (ask[i][0]==0&&j>1){
j--;
key[j]=min(query(1,1,n,j),query(1,1,n,j-1));
father[j]=tree[j][0]=tree[j][1]=0;
insert(root,j);
splay(j,0);
}
else if (ask[i][0]==1&&j<n){
splay(j,0);
clear(j);
father[tree[j][0]]=father[tree[j][1]]=0;
root=merge(tree[j][0],tree[j][1]);
j++;
}
else if (ask[i][0]==3){
now-=find2(root);
t=ask[i][p+1]-(query(1,1,n,j)-query(1,1,n,j-1));
splay(j,0);
clear(j);
father[tree[j][0]]=father[tree[j][1]]=0;
root=merge(tree[j][0],tree[j][1]);
mark2(root,t);
change(1,1,n,j,n,t);
key[j]=min(query(1,1,n,j),query(1,1,n,j-1));
father[j]=tree[j][0]=tree[j][1]=0;
insert(root,j);
splay(j,0);
now+=find2(root);
}
else if (ask[i][0]==2) ans[ask[i][1]]-=now;
}
fo(i,1,tot) ans[i]+=n;
}
int main(){
//freopen("data.in","r",stdin);freopen("data.out","w",stdout);
n=read();
a[0][0]=a[0][1]=1;
fo(i,1,n) a[i][0]=read(),a[i][1]=read();
m=read();
fo(i,1,m){
ch=get();
if (ch=='B') ask[i][0]=0;
else if (ch=='F') ask[i][0]=1;
else if (ch=='Q') ask[i][0]=2,ask[i][1]=++tot;
else{
ask[i][0]=3;
ask[i][1]=read();ask[i][2]=read();
}
}
work(0);
work(1);
fo(i,1,tot) printf("%d\n",ans[i]);
}