每个房间用一个集合来维护,具体来说,就是给1-n的数每个数一个long long的hash值,往集合S里insert(i),就是S^=HASH[i];erase(i),也是S^=HASH[i]。

用map/set维护某个集合是否已经做过实验。

分块,对每个块维护一个maxv[i],代表当前该块内的答案值,要注意,若某个房间的集合的vis[S[i]]==true,则它对其所在块没有贡献。

分块相对于线段树/平衡树/树套树的很大的好处,就是思路简单暴力,代码短,常数小,应对范围广,可以方便地扩张。

像这种区间修改的问题,可以类比线段树打懒标记的思路来进行,使得每次修改是O(sqrt(n))的。

Pushdown函数需要每次对块进行“零散地”操作的之前进行。

 #include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<map>
using namespace std;
unsigned long long HASH[];
struct SET
{
unsigned long long S;int size;
void insert(const int &v){S^=HASH[v];size++;}
void erase(const int &v){S^=HASH[v];size--;}
};
int n,m,q,l[],r[],sumv[],sum,sz,num[],x,y,pos[];
bool delta[];
SET sets[];
map<unsigned long long,bool>vis;
char op[];
int Res,Num;char C,CH[];
inline int G()
{
Res=;C='*';
while(C<''||C>'')C=getchar();
while(C>=''&&C<=''){Res=Res*+(C-'');C=getchar();}
return Res;
}
inline void P(long long x)
{
Num=;if(!x){putchar('');puts("");return;}
while(x>)CH[++Num]=x%,x/=;
while(Num)putchar(CH[Num--]+);
puts("");
}
void makeblock()
{
srand();
for(int i=;i<=n;i++) HASH[i]=(unsigned long long)((unsigned long long)rand()<<)|((unsigned long long)rand()<<)|((unsigned long long)rand()<<)|((unsigned long long)rand());
sz=sqrt((double)m*0.3);
for(int i=;i<=n;i++) {sets[].insert(i); pos[i]=;}
sumv[]=n;
for(sum=;sum*sz<m;sum++)
{
l[sum]=(sum-)*sz+;
r[sum]=sum*sz;
for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
}
l[sum]=sz*(sum-)+; r[sum]=m;
for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
}
inline void Pushdown(const int &p)//对块p下传标记,Pushdown操作需要每次对块进行零散操作之前进行
{
if(delta[p])
{
for(int i=l[p];i<=r[p];i++)
if(sets[i].size)
vis[sets[i].S]=true;
delta[p]=false;
}
}
inline void Move()
{
Pushdown(num[pos[x]]);
bool flag1=vis[sets[pos[x]].S];
sets[pos[x]].erase(x);
bool flag2=vis[sets[pos[x]].S];
if(flag1&&!flag2) sumv[num[pos[x]]]+=sets[pos[x]].size;
else if(!flag1&&flag2) sumv[num[pos[x]]]-=(sets[pos[x]].size+);
else if(!flag1&&!flag2) sumv[num[pos[x]]]--;
Pushdown(num[y]);
flag1=vis[sets[y].S];
sets[y].insert(x);
flag2=vis[sets[y].S];
if(flag1&&!flag2) sumv[num[y]]+=sets[y].size;
else if(!flag1&&flag2) sumv[num[y]]-=(sets[y].size-);
else if(!flag1&&!flag2) sumv[num[y]]++;
pos[x]=y;
}
inline void Update_Query()
{
int ans=;
Pushdown(num[x]);
Pushdown(num[y]);
if(num[x]+>=num[y])
{
for(int i=x;i<=y;i++)
if(sets[i].size)
if(!vis[sets[i].S])
{
ans+=sets[i].size;
sumv[num[i]]-=sets[i].size;
vis[sets[i].S]=true;
}
}
else
{
for(int i=x;i<=r[num[x]];i++)
if(sets[i].size)
if(!vis[sets[i].S])
{
ans+=sets[i].size;
sumv[num[x]]-=sets[i].size;
vis[sets[i].S]=true;
}
for(int i=l[num[y]];i<=y;i++)
if(sets[i].size)
if(!vis[sets[i].S])
{
ans+=sets[i].size;
sumv[num[y]]-=sets[i].size;
vis[sets[i].S]=true;
}
for(int i=num[x]+;i<num[y];i++)
{
if(!delta[i])
ans+=sumv[i];
delta[i]=true;
sumv[i]=;
}
}
P(ans);
}
int main()
{
n=G();m=G();q=G();
makeblock();
for(;q>;q--)
{
scanf("%s",op);x=G();y=G();
if(op[]=='C') Move();
else Update_Query();
}
return ;
}

【分块】【哈希】bzoj3578 GTY的人类基因组计划2的更多相关文章

  1. BZOJ3578:GTY的人类基因组计划2(集合hash,STL)

    Description GTY召唤了n个人来做实验,GTY家的房子很大,有m个房间一开始所有人都在1号房间里,GTY会命令某人去某个房间等待做实验,或者命令一段区间的房间开始实验,实验会获得一些实验信 ...

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

    关于如何判断一个集合是否出现过: 给每个元素随机一个hash权值,然后xor起来即可 插入删除都只需xor 线段树维护区间有效人数和,以及打标记表示这个区间的集合要全部标记为出现过,并把区间内sum值 ...

  3. 【BZOJ-3578】GTY的人类基因组计划2 set + map + Hash 乱搞

    3578: GTY的人类基因组计划2 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 367  Solved: 159[Submit][Status][ ...

  4. HDU 4391 - Paint The Wall - 分块哈希入门

    题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=4391 题意 : 给一段区间, 有两种操作 1 : 给 x 到 y 的区间染色为 z 2 : 查询 ...

  5. Codeforces 1340F - Nastya and CBS(分块+哈希)

    Codeforces 题面传送门 & 洛谷题面传送门 首先看到这样的数据范围我们可以考虑分块,具体来说,对于每一块我们记录其中的括号是否能完全消掉,以及对其进行括号相消之后的括号序列(显然是一 ...

  6. NOIP2018 - 暑期博客整理

    暑假写的一些博客复习一遍.顺便再写一遍或者以现在的角度补充一点东西. 盛暑七月 初涉基环外向树dp&&bzoj1040: [ZJOI2008]骑士 比较经典的基环外向树dp.可以借鉴的 ...

  7. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  8. CHAPTER 38 Reading ‘the Book of Life’ The Human Genome Project 第38章 阅读生命之书 人体基因组计划

    CHAPTER 38 Reading ‘the Book of Life’ The Human Genome Project 第38章 阅读生命之书 人体基因组计划 Humans have about ...

  9. AI-Info-Micron:人如其食:人工智能和人类微生物组

    ylbtech-AI-Info-Micron:人如其食:人工智能和人类微生物组 1.返回顶部 1. 人如其食:人工智能和人类微生物组 “相信你身体发出的信号”,的确是一个很好的建议.研究人员在不遗余力 ...

随机推荐

  1. [poj 3436]最大流+输出结果每条边流量

    题目链接:http://poj.org/problem?id=3436 大力套kuangbin板过了orz #include<cstdio> #include<cstring> ...

  2. Linux设置虚拟内存-创建和启用Swap交换区

    如果你的服务器的总是报告内存不足,并且时常因为内存不足而引发服务被强制kill的话,在不增加物理内存的情况下,启用swap交换区作为虚拟内存是一个不错的选择,如果是SSD硬盘,正常读写速度都在300M ...

  3. 小程序根据input输入,动态设置按钮的样式

    [需求]实现当手机号已填写和协议已勾选时,“立即登录”按钮变亮,按钮可点击:若有一个不满足,按钮置灰,不可点击:实现获取短信验证码,倒计时提示操作:对不满足要求内容进行toast弹窗提示. <v ...

  4. BigDecimal与Long、int之间的互换

    在实际开发过程中BigDecimal是一个经常用到的数据类型,它和int Long之间可以相互转换. 转换关系如下代码展示: int 转换成 BigDecimal 数据类型 //int 转换成 big ...

  5. 会议中心[APIO2009]

    会议中心 思路 这一题的正解是倍增的,但是由于我太蒟蒻了,所以我选了一个不算正解但是有可以拿满分的题目学习 思路和我考场上其实差不多,只是我无法实现.... 下面我先来介绍几个数组的用途 1.s,s数 ...

  6. bzoj 2245 费用流

    比较裸 源点连人,每个人连自己的工作,工作连汇,然后因为人的费用是 分度的,且是随工作数非降的,所以我们拆边,源点连到每个人s+1条边 容量是每段的件数,费用是愤怒 /**************** ...

  7. C# 从服务器下载文件

    一.//TransmitFile实现下载 protected void Button1_Click(object sender, EventArgs e) { /* 微软为Response对象提供了一 ...

  8. CVE-2016-6662 mysql RCE测试

    参考:http://bobao.360.cn/learning/detail/3027.html ,我尝试第一种方法 1.先修改mysql_hookandroot_lib.c里面的反弹地址和端口: # ...

  9. python—用for循环、while循环和一句话打印九九乘法表

    用for循环打印九九乘法表: for i in range (1,10): for j in range(1,10): print(j,"x",i,"=",i* ...

  10. swift关于is和as的解释

    http://tieba.baidu.com/p/3155277323 在Swift中,类型检查使用is和as操作符来实现. is操作符用来检查一个实例是否是某种特定类型,如果是返回true,否则返回 ...