每个房间用一个集合来维护,具体来说,就是给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. Spring源码解析-基于注解依赖注入

    在spring2.5版本提供了注解的依赖注入功能,可以减少对xml配置. 主要使用的是 AnnotationConfigApplicationContext: 一个注解配置上下文 AutowiredA ...

  2. Django请求原理

    总结一下: 1. 进来的请求转入/hello/. 2. Django通过在ROOT_URLCONF配置来决定根URLconf. 3. Django在URLconf中的所有URL模式中,查找第一个匹配/ ...

  3. Qt 设置应用程序图标(windows)

    Step 1: 创建  xxx.rc 文件. 将ico图标文件复制到项目根目录下.然后在该目录中新建xxx.rc文件,并输入一行代码: IDI_ICON1 ICON DISCARDABLE " ...

  4. jquery序列化表单

    没有使用其他的东西 , 数据传送是最基本的. 前台: var info = $('#dataForm').serialize() ; alert(decodeURIComponent(info,tru ...

  5. NodeJS概述

    NodeJS中文API 一.概述 Node.js 是一种建立在Google Chrome’s v8 engine上的 non-blocking (非阻塞), event-driven (基于事件的) ...

  6. 记另类Request method 'GET' not supported

    一般遇到Request method 'GET' not supported这种问题,大家都会找相应controller下的具体方法,把get改为post之类.但是我这次是在访问静态资源,static ...

  7. eclipse怎样快速的给代码段添加try catch

    打开要进行异常处理的java代码页面. 选中要添加try..catch的代码段,然后点击鼠标右键,选择[Sourround With]选项. 然后选择[Try/Catch Block]或者[6 try ...

  8. SDK登录cognos

    通过SDK登录cognos 一种是拼xml,如这里的实现https://github.com/cosysoft/cognos-tools/blob/master/src/com/ibm/cognos/ ...

  9. 【BZOJ2227】【ZJOI2011】看电影 [组合数][质因数分解]

    看电影 Time Limit: 10 Sec  Memory Limit: 259 MB[Submit][Status][Discuss] Description 到了难得的假期,小白班上组织大家去看 ...

  10. bzoj1574 [Usaco2009 Jan]地震损坏Damage

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1574 [题解] 贪心把report的点的旁边所有点破坏即可. # include <s ...