BZOJ3578 : GTY的人类基因组计划2

关于如何判断一个集合是否出现过:

给每个元素随机一个hash权值,然后xor起来即可

插入删除都只需xor

线段树维护区间有效人数和,以及打标记表示这个区间的集合要全部标记为出现过,并把区间内sum值都置0

写hash用了map被虐了TAT

#include<cstdio>
#include<map>
#define N 100010
#define M 200010
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
int n,m,q,i,j,loc[N];
int tot,l[M],r[M],val[M],sum[M],ran,set[M],hash[N];bool tag[M];
std::map<int,bool>vis;
char ch;
int build(int a,int b){
int x=++tot;
if(a==b)return x;
int mid=(a+b)>>1;
l[x]=build(a,mid);r[x]=build(mid+1,b);
return x;
}
inline void clean(int x,int a,int b){
if(!x)return;
tag[x]=1;sum[x]=0;
if(a==b)vis[set[x]]=1;
}
inline void pb(int x,int a,int b){
if(tag[x]){
int mid=(a+b)>>1;
clean(l[x],a,mid);clean(r[x],mid+1,b);
tag[x]=0;
}
}
inline void up(int x){sum[x]=sum[l[x]]+sum[r[x]];}
void add(int x,int a,int b,int c,int p,int w){
if(a==b){
set[x]^=p;
val[x]+=w;
sum[x]=vis[set[x]]?0:val[x];
return;
}
int mid=(a+b)>>1;
pb(x,a,b);
if(c<=mid)add(l[x],a,mid,c,p,w);else add(r[x],mid+1,b,c,p,w);
up(x);
}
int ask(int x,int a,int b,int c,int d){
int t=0;
if(c<=a&&b<=d){
t=sum[x];
clean(x,a,b);
return t;
}
int mid=(a+b)>>1;
pb(x,a,b);
if(c<=mid)t+=ask(l[x],a,mid,c,d);
if(d>mid)t+=ask(r[x],mid+1,b,c,d);
up(x);
return t;
}
int main(){
read(n),read(m),read(q);
build(1,m);
for(i=1;i<=n;i++)ran*=233,ran+=17,add(1,1,m,loc[i]=1,hash[i]=ran,1);
while(q--){
while(!(((ch=getchar())=='C')||(ch=='W')));
read(i),read(j);
if(ch=='C')add(1,1,m,loc[i],hash[i],-1),add(1,1,m,loc[i]=j,hash[i],1);
else printf("%d\n",ask(1,1,m,i,j));
}
return 0;
}

  

上一篇:敲点JavaScript代码


下一篇:Excel公式使用