题意:
给你长为n的数组,每次有两种操作:
> x 将所有大于x的数*-1
< x 将所有小于x的数*-1
问你经过q次操作之后,最终的数组是什么样子的
题解:
这种题目一看就不能直接做,然后它的数的范围只有-1e5~1e5,其实就算再大,离散化一下也能做。那么接下来就是分情况了,首先第一种操作:
假设x>=0
那么就相当于>x的所有数都要乘-1,<-x的都要乘1。
那么如果x<0
-x+1到x-1的所有数,无论他们是正是负都要变换一下符号位,也就是*-1,然后两边的话就像上边一样即可。
对于<的情况也类似。
就是赋值和下传标记的时候注意一下。
我这里f1表示翻转操作,f2表示赋值操作。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10,ad=1e5+2;
int val[N*4],f1[N*4],f2[N*4];
int a[N];
void push_down(int root){
if(f1[root]){
val[root<<1]*=-1;
val[root<<1|1]*=-1;
f1[root<<1]^=1;
f1[root<<1|1]^=1;
f2[root<<1]*=-1;
f2[root<<1|1]*=-1;
f1[root]=0;
}
if(f2[root]){
val[root<<1]=val[root<<1|1]=f2[root];
f1[root<<1]=f1[root<<1|1]=0;
f2[root<<1]=f2[root<<1|1]=f2[root];
f2[root]=0;
}
}
void update(int l,int r,int root,int ql,int qr,int op,int v){
if(l>=ql&&r<=qr){
if(op==1)
val[root]*=-1,f1[root]^=1,f2[root]*=-1;
else
val[root]=v,f2[root]=v,f1[root]=0;
return ;
}
int mid=l+r>>1;
push_down(root);
if(mid>=ql)
update(l,mid,root<<1,ql,qr,op,v);
if(mid<qr)
update(mid+1,r,root<<1|1,ql,qr,op,v);
}
int query(int l,int r,int root,int p){
if(l==r)
return val[root];
int mid=l+r>>1;
push_down(root);
if(mid>=p)
return query(l,mid,root<<1,p);
else
return query(mid+1,r,root<<1|1,p);
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=ad*2*4;i++)
val[i]=1;
while(k--){
char s[2];
int x;
scanf("%s%d",s,&x);
if(s[0]=='>'){
if(x>=0){
update(1,2*ad,1,x+1+ad,2*ad,2,-1);
update(1,2*ad,1,1,ad-x-1,2,1);
//printf("%d\n",query(1,2*ad,1,2+ad));
}
else{
update(1,2*ad,1,ad+x+1,ad-x-1,1,1);
update(1,2*ad,1,1,ad+x,2,1);
update(1,2*ad,1,ad-x,2*ad,2,-1);
}
}
else{
if(x>0){
update(1,2*ad,1,ad-x+1,ad+x-1,1,1);
update(1,2*ad,1,1,ad-x,2,-1);
update(1,2*ad,1,ad+x,2*ad,2,1);
}
else{
update(1,2*ad,1,1,ad+x-1,2,-1);
update(1,2*ad,1,ad-x+1,2*ad,2,1);
}
}
}
for(int i=1;i<=n;i++)
printf("%d%c",a[i]*query(1,2*ad,1,ad+a[i])," \n"[i==n]);
return 0;
}