每个房间用一个集合来维护,具体来说,就是给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. [ST表/贪心] NOI2010 超级钢琴

    [NOI2010]超级钢琴 题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i ...

  2. wait , notify 模拟 Queue

    package com.itdoc.multi.sync009; import java.util.LinkedList; import java.util.concurrent.TimeUnit; ...

  3. HDU2553 N皇后问题---(dfs)

    http://acm.hdu.edu.cn/showproblem.php?pid=2553 在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在 ...

  4. 动态规划&字符串:最长公共子串

    还是直接上转移方程: 动规只能解决O(n^2)的最长公共子串问题 使用后缀数组或者SAM可以高效地解决这个问题 所以,对于这个问题,动规的代码就不给出了 直接给出SAM的实现,也为以后学习SAM打下一 ...

  5. 【FJWC2017】交错和查询 [线段树]

    交错和查询 Time Limit: 10 Sec  Memory Limit: 256 MB Description 无限循环数字串S由长度为n的循环节s构成.设s为12345(n=5),则数字串S为 ...

  6. [bzoj1717][Usaco2006 Dec]Milk Patterns 产奶的模式——后缀数组

    Brief Description 给定一个字符串,求至少出现k次的最长重复子串. Algorithm Design 先二分答案,然后将后缀分成若干组.判断有没有一个组的后缀个数不小于k.如果有,那么 ...

  7. python-列表 字典 集合 元祖 字符串的相关总结练习

    1.执行python脚本的两种方式指定解释器执行在交互器中执行 2.简述位.字节的关系:ASCII1个二进制位是计算机里的最小表示单元1个字节是计算机里最小的储存单元二进制位=8bits(位)8bit ...

  8. Opencv 中透视变换函数对IplImage图像变换时出现的问题?

    最近一直在做视频稳像的项目,为了简化部分实现,使用了部分Opencv的函数,其中包括Opencv中对IplImage进行同时变换的函数cvWarpPerspective(src, dst,...) 发 ...

  9. Js使用WScript.Shell对象执行.bat文件和cmd命令

    Js使用WScript.Shell对象执行.bat文件和cmd命令 http://www.jb51.net/article/58669.htm WScript.Shell(Windows Script ...

  10. Mac-装机

    不过大家可别被「命令行」三个字吓到,其实你只需按步骤来,复制粘贴命令即可快速完成,事实上是很简单的. 一.准备工作: 准备一个 8GB 或以上容量的 U 盘,确保里面的数据已经妥善备份好(该过程会抹掉 ...