• 【函数式权值分块】【分块】bzoj1901 Zju2112 Dynamic Rankings


    论某O(n*sqrt(n))的带修改区间k大值算法。

    首先对序列分块,分成sqrt(n)块。

    然后对权值分块,共维护sqrt(n)个权值分块,对于权值分块T[i],存储了序列分块的前i块的权值情况。

    对于区间询问,需要获得区间中每个值出现的次数,然后按权值扫O(sqrt(n)),完整的部分我们可以通过权值分块差分(O(1))得到(比如Lb~Rb块就是T[Rb]-T[Lb-1]),零散的部分我们再维护一个额外的权值分块,累计上该值即可。O(sqrt(n))。

    对于修改,直接在该位置之后的所有权值分块里修改,单次修改O(1),涉及O(sqrt(n))个权值分块,所以是O(sqrt(n))的。

    所以平均每次操作是O(sqrt(n))的,空间复杂度是O(n*sqrt(n))的。

    (缺陷:①必须离散化;②空间复杂度较高,对n=100000,几乎会卡空间)

    这份代码目前在 bzoj 上 Rank1

    No. RunID User Memory Time Language Code_Length Submit_Time
    1 802901(8) lizitong 10192 KB 208 MS C++ 3468 B 2014-12-11 13:01:16
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int Num,CH[12],f,c;
    inline void R(int &x){
        c=0;f=1;
        for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
        for(x=0;c>='0'&&c<='9';c=getchar())(x*=10)+=(c-'0');
        x*=f;
    }
    inline void P(int x){
        if(x<10)putchar(x+'0');
        else{P(x/10);putchar(x%10+'0');}
    }
    struct Point{int v,p;}t[20001];
    bool operator < (const Point &a,const Point &b){return a.v<b.v;}
    int n,m,xs[10001],ys[10001],ks[10001],sum=1,en,en2,ma[20001],l[111],r[111];
    int a[20001],num[10001],num2[20001],l2[145];
    char op[10001];
    struct Val_Block
    {
    	int b[20001],sumv[145];
    	void Insert(const int &x){++b[x]; ++sumv[num2[x]];}
    	void Delete(const int &x){--b[x]; --sumv[num2[x]];}
    }T[111],S;
    int Kth(const int &L,const int &R,const int &x)
    {
    	int cnt=0,res;
    	if(num[L]+1>=num[R])
    	  {
    	  	for(int i=L;i<=R;++i) S.Insert(a[i]);
    	  	for(int i=1;;++i)
              {
                cnt+=S.sumv[i];
                if(cnt>=x)
                  {
                    cnt-=S.sumv[i];
                    for(int j=l2[i];;++j)
                    {cnt+=S.b[j]; if(cnt>=x) {res=j; goto OUT2;}}
                  }
              } OUT2:
            for(int i=L;i<=R;++i) S.Delete(a[i]);
            return res;
    	  }
    	for(int i=L;i<=r[num[L]];++i) S.Insert(a[i]);
    	for(int i=l[num[R]];i<=R;++i) S.Insert(a[i]);
        int LB=num[L],RB=num[R]-1;
        for(int i=1;;++i)
          {
            cnt+=(T[RB].sumv[i]-T[LB].sumv[i]+S.sumv[i]);
            if(cnt>=x)
              {
                cnt-=(T[RB].sumv[i]-T[LB].sumv[i]+S.sumv[i]);
                for(int j=l2[i];;++j)
                {cnt+=(T[RB].b[j]-T[LB].b[j]+S.b[j]); if(cnt>=x) {res=j; goto OUT;}}
              }
          } OUT:
    	for(int i=L;i<=r[num[L]];++i) S.Delete(a[i]);
    	for(int i=l[num[R]];i<=R;++i) S.Delete(a[i]);
    	return res;
    }
    void makeblock()
    {
    	int sz=sqrt(n); if(!sz) sz=1;
    	for(;sum*sz<n;++sum)
    	  {
    	  	l[sum]=r[sum-1]+1; r[sum]=sum*sz;
    	  	for(int i=l[sum];i<=r[sum];++i) num[i]=sum;
    	  }
    	l[sum]=r[sum-1]+1; r[sum]=n;
    	for(int i=l[sum];i<=r[sum];++i) num[i]=sum;
    }
    void val_mb()
    {
    	int tot=1,sz=sqrt(en2); if(!sz) sz=1;
    	for(;tot*sz<en2;++tot)
    	  {
    	  	l2[tot]=(tot-1)*sz+1;
    	  	int R=tot*sz;
    	  	for(int i=l2[tot];i<=R;++i) num2[i]=tot;
    	  }
    	l2[tot]=(tot-1)*sz+1;
    	for(int i=l2[tot];i<=en2;++i) num2[i]=tot;
    }
    void Init_Ts()
    {
    	for(int i=1;i<=sum;++i)
    	  {
    	  	T[i]=T[i-1];
    	  	for(int j=l[i];j<=r[i];++j) T[i].Insert(a[j]);
    	  }
    }
    int main()
    {
    	R(n); R(m); en=n; makeblock();
    	for(int i=1;i<=n;++i) {R(t[i].v); t[i].p=i;} getchar();
    	for(int i=1;i<=m;++i)
    	  {
    	  	op[i]=getchar(); R(xs[i]); R(ys[i]);
    	  	if(op[i]=='Q') R(ks[i]);
    	  	else {t[++en].v=ys[i]; t[en].p=en;}
    	  }
    	sort(t+1,t+en+1);
    	ma[a[t[1].p]=++en2]=t[1].v;
        for(int i=2;i<=en;++i)
          {
            if(t[i].v!=t[i-1].v) ++en2;
            ma[a[t[i].p]=en2]=t[i].v;
          }
    	val_mb(); Init_Ts(); en=n;
        for(int i=1;i<=m;++i)
          {
          	if(op[i]=='C')
          	  {
          	  	++en;
          	  	for(int j=num[xs[i]];j<=sum;++j)
    		      T[j].Delete(a[xs[i]]),T[j].Insert(a[en]);
    		    a[xs[i]]=a[en];
          	  }
    		else P(ma[Kth(xs[i],ys[i],ks[i])]),puts("");
          }
    	return 0;
    }
    
  • 相关阅读:
    OpenCV---在图片上加入文字
    DosBox 报错 this program requires dosxnt.exe to be in your path
    iOS开发-UITableView单选多选/复选实现1
    LeetCode第七题,Reverse Integer
    【PostgreSQL】PostgreSQL操作-psql基本命令
    Bootstrap的js插件之弹出框(popover)
    Qt Quick 图像处理实例之美图秀秀(附源代码下载)
    【甘道夫】并行化频繁模式挖掘算法FP Growth及其在Mahout下的命令使用
    用Visual Studio高版本号打开低版本号的project,转换时出现错误:fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
    如何安装ArchLinux
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/4157365.html
Copyright © 2020-2023  润新知