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 }
  • 相关阅读:
    二进制位运算
    Leetcode 373. Find K Pairs with Smallest Sums
    priority_queue的用法
    Leetcode 110. Balanced Binary Tree
    Leetcode 104. Maximum Depth of Binary Tree
    Leetcode 111. Minimum Depth of Binary Tree
    Leetcode 64. Minimum Path Sum
    Leetcode 63. Unique Paths II
    经典的递归练习
    案例:java中的基本排序
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/4034867.html
Copyright © 2011-2022 走看看