zoukankan      html  css  js  c++  java
  • 【分块】【哈希】bzoj3578 GTY的人类基因组计划2

    每个房间用一个集合来维护,具体来说,就是给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函数需要每次对块进行“零散地”操作的之前进行。

      1 #include<cstdio>
      2 #include<cmath>
      3 #include<algorithm>
      4 #include<cstdlib>
      5 #include<ctime>
      6 #include<map>
      7 using namespace std;
      8 unsigned long long HASH[100001];
      9 struct SET
     10 {
     11     unsigned long long S;int size;
     12     void insert(const int &v){S^=HASH[v];size++;}
     13     void erase(const int &v){S^=HASH[v];size--;}
     14 };
     15 int n,m,q,l[600],r[600],sumv[600],sum,sz,num[100001],x,y,pos[100001];
     16 bool delta[600];
     17 SET sets[100001];
     18 map<unsigned long long,bool>vis;
     19 char op[1];
     20 int Res,Num;char C,CH[12];
     21 inline int G()
     22 {
     23     Res=0;C='*'; 
     24     while(C<'0'||C>'9')C=getchar();
     25     while(C>='0'&&C<='9'){Res=Res*10+(C-'0');C=getchar();}
     26     return Res;
     27 }
     28 inline void P(long long x)
     29 {
     30     Num=0;if(!x){putchar('0');puts("");return;}
     31     while(x>0)CH[++Num]=x%10,x/=10;
     32     while(Num)putchar(CH[Num--]+48);
     33     puts("");
     34 }
     35 void makeblock()
     36 {
     37     srand(233);
     38     for(int i=1;i<=n;i++) HASH[i]=(unsigned long long)((unsigned long long)rand()<<48)|((unsigned long long)rand()<<32)|((unsigned long long)rand()<<16)|((unsigned long long)rand());
     39     sz=sqrt((double)m*0.3);
     40     for(int i=1;i<=n;i++) {sets[1].insert(i); pos[i]=1;}
     41     sumv[1]=n;
     42     for(sum=1;sum*sz<m;sum++)
     43       {
     44         l[sum]=(sum-1)*sz+1;
     45         r[sum]=sum*sz;
     46         for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
     47       }
     48     l[sum]=sz*(sum-1)+1; r[sum]=m;
     49     for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
     50 }
     51 inline void Pushdown(const int &p)//对块p下传标记,Pushdown操作需要每次对块进行零散操作之前进行
     52 {
     53     if(delta[p])
     54       {
     55           for(int i=l[p];i<=r[p];i++)
     56           if(sets[i].size)
     57             vis[sets[i].S]=true;
     58         delta[p]=false;
     59       }
     60 }
     61 inline void Move()
     62 {
     63     Pushdown(num[pos[x]]);
     64     bool flag1=vis[sets[pos[x]].S];
     65     sets[pos[x]].erase(x);
     66     bool flag2=vis[sets[pos[x]].S];
     67     if(flag1&&!flag2) sumv[num[pos[x]]]+=sets[pos[x]].size;
     68     else if(!flag1&&flag2) sumv[num[pos[x]]]-=(sets[pos[x]].size+1);
     69     else if(!flag1&&!flag2) sumv[num[pos[x]]]--;
     70     Pushdown(num[y]);
     71     flag1=vis[sets[y].S];
     72     sets[y].insert(x);
     73     flag2=vis[sets[y].S];
     74     if(flag1&&!flag2) sumv[num[y]]+=sets[y].size;
     75     else if(!flag1&&flag2) sumv[num[y]]-=(sets[y].size-1);
     76     else if(!flag1&&!flag2) sumv[num[y]]++;
     77     pos[x]=y;
     78 }
     79 inline void Update_Query()
     80 {
     81     int ans=0;
     82     Pushdown(num[x]);
     83     Pushdown(num[y]);
     84     if(num[x]+1>=num[y])
     85       {
     86         for(int i=x;i<=y;i++)
     87           if(sets[i].size)
     88             if(!vis[sets[i].S])
     89               {
     90                   ans+=sets[i].size;
     91                   sumv[num[i]]-=sets[i].size;
     92                 vis[sets[i].S]=true;
     93               }
     94       }
     95     else
     96       {
     97           for(int i=x;i<=r[num[x]];i++)
     98             if(sets[i].size)
     99             if(!vis[sets[i].S])
    100               {
    101                   ans+=sets[i].size;
    102                   sumv[num[x]]-=sets[i].size;
    103                 vis[sets[i].S]=true;
    104               }
    105           for(int i=l[num[y]];i<=y;i++)
    106             if(sets[i].size)
    107             if(!vis[sets[i].S])
    108               {
    109                   ans+=sets[i].size;
    110                   sumv[num[y]]-=sets[i].size;
    111                 vis[sets[i].S]=true;
    112               }
    113           for(int i=num[x]+1;i<num[y];i++)
    114           {
    115             if(!delta[i])
    116               ans+=sumv[i];
    117             delta[i]=true;
    118             sumv[i]=0;
    119           }
    120       }
    121     P(ans);
    122 }
    123 int main()
    124 {
    125     n=G();m=G();q=G();
    126     makeblock();
    127     for(;q>0;q--)
    128       {
    129           scanf("%s",op);x=G();y=G(); 
    130           if(op[0]=='C') Move();
    131           else Update_Query();
    132       }
    133     return 0;
    134 }
  • 相关阅读:
    Linux学习笔记(八)权限管理命令
    Linux学习笔记(七)关机、重启及常用的网络命令
    Linux学习笔记(六)压缩和解压缩命令
    Linux学习笔记(五)搜索命令
    Linux学习笔记(四)帮助命令
    Linux学习笔记(三)目录和文件都能操作的命令
    Linux学习笔记(二)文件操作命令
    Linux学习笔记(一)目录处理命令
    面试题((A)null).fun()——java中null值的强转
    idea注册码
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/4034867.html
Copyright © 2011-2022 走看看