zoukankan      html  css  js  c++  java
  • 【ZOJ2112】Dynamic Rankings-树状数组套主席树+离散化

    测试地址:Dynamic Rankings

    题目大意:维护一个长度为N的数列,支持以下操作:询问区间[i,j]内的第k小的元素,修改一个元素。

    做法:这是一个很经典的问题:带单点修改的求区间第k小值问题。在我以前写的题解中我简述了用主席树求解不带修改的求区间第k小值问题的方法,那么今天这个带单点修改的问题要怎么办呢?我们知道在求解这类问题时,主席树中的各棵线段树实质上是一种前缀和,那么维护静态的区间和可以用前缀和维护,维护动态的区间和可以用树状数组维护,所以在这里就可以用树状数组套主席树来解决问题。在前面静态的问题中,第i棵线段树表示[1,i]这个区间内数的出现次数,利用将前缀和转化成树状数组的方法,转化之后的树状数组套主席树中的第i棵线段树表示[i-lowbit(i)+1,i]区间内数的出现次数,于是在修改某个元素时,运用类似树状数组维护动态前缀和的方法来维护与该元素相关的每棵线段树即可。询问区间[l,r]时将与元素A[l-1]和A[r]相关的各棵树的树根记录下来,然后再用类似静态问题中的二分查找方法查找即可。

    可是这道题在ZOJ上的空间卡得很紧:32M,直接运用树状数组套主席树的方法的空间复杂度是O((N+M)log^2 N),会MLE,这时我们就用与处理静态问题时相同的一棵主席树维护原数列,再用一棵树状数组套主席树来维护在原数列基础上修改的值,这样空间复杂度降为O(NlogN+Mlog^2 N),可以用25M左右的空间AC。当然,原数列中元素的值可达10^9,需要将所有原数列中元素的值和修改操作中元素修改后的值离散化。这样问题就完美解决了。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int T,n,m,a[50010],ops[10010][3],rt1[50010],rt2[50010],f,tot;
    int L[50010],R[50010];
    char op[10010][5];
    struct forsort
    {
      int val,pos;
    }fs[100010];
    struct segnode
    {
      int lc,rc;
      int sum;
    }seg[2000010];
    
    int lowbit(int x)
    {
      return x&(-x);
    }
    
    bool cmp(forsort a,forsort b)
    {
      return a.val<b.val;
    }
    
    void trarr(int x,int *g)
    {
      g[0]=0;
      for(;x>=1;x-=lowbit(x))
        g[++g[0]]=rt2[x];
    }
    
    void buildtree(int &no,int l,int r)
    {
      no=++tot;
      seg[no].lc=seg[no].rc=seg[no].sum=0;
      if (l==r) return;
      int mid=(l+r)>>1;
      buildtree(seg[no].lc,l,mid);
      buildtree(seg[no].rc,mid+1,r);
    }
    
    void insert(int &no,int last,int l,int r,int k,int c)
    {
      no=++tot;
      seg[no]=seg[last];
      if (l==r)
      {
        seg[no].sum+=c;
    	return;
      }
      int mid=(l+r)>>1;
      if (k<=mid) insert(seg[no].lc,seg[last].lc,l,mid,k,c);
      else insert(seg[no].rc,seg[last].rc,mid+1,r,k,c);
      seg[no].sum=seg[seg[no].lc].sum+seg[seg[no].rc].sum;
    }
    
    int query(int fnt,int lst,int l,int r,int k)
    {
      int s=seg[seg[lst].lc].sum-seg[seg[fnt].lc].sum,mid=(l+r)>>1;
      if (l==r) return l;
      for(int i=1;i<=R[0];i++)
        s+=seg[seg[R[i]].lc].sum;
      for(int i=1;i<=L[0];i++)
        s-=seg[seg[L[i]].lc].sum;
      if (s>=k)
      {
        for(int i=1;i<=R[0];i++)
    	  R[i]=seg[R[i]].lc;
    	for(int i=1;i<=L[0];i++)
    	  L[i]=seg[L[i]].lc;
    	return query(seg[fnt].lc,seg[lst].lc,l,mid,k);
      }
      else
      {
        for(int i=1;i<=R[0];i++)
    	  R[i]=seg[R[i]].rc;
    	for(int i=1;i<=L[0];i++)
    	  L[i]=seg[L[i]].rc;
    	return query(seg[fnt].rc,seg[lst].rc,mid+1,r,k-s);
      }
    }
    
    int main()
    {
      scanf("%d",&T);
      while(T--)
      {
        tot=0;
        scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    	{
    	  scanf("%d",&fs[i].val);
    	  fs[i].pos=i;
    	}
    	f=n;
    	for(int i=1;i<=m;i++)
    	{
    	  scanf("%s",op[i]);
    	  if (op[i][0]=='Q') scanf("%d%d%d",&ops[i][0],&ops[i][1],&ops[i][2]);
    	  if (op[i][0]=='C')
    	  {
    	    scanf("%d%d",&ops[i][0],&fs[++f].val);
    		fs[f].pos=n+i;
    	  }
    	}
    	
    	sort(fs+1,fs+f+1,cmp);
    	for(int i=1;i<=f;i++)
    	{
    	  if (fs[i].pos<=n) a[fs[i].pos]=i;
    	  else ops[fs[i].pos-n][1]=i;
    	}
    	
    	buildtree(rt1[0],1,f);
    	for(int i=1;i<=n;i++)
    	  insert(rt1[i],rt1[i-1],1,f,a[i],1);
    	buildtree(rt2[0],1,f);
    	for(int i=1;i<=n;i++)
    	  rt2[i]=rt2[0];
    	
    	for(int i=1,s,t,c;i<=m;i++)
    	{
    	  if (op[i][0]=='Q')
    	  {
    	    s=ops[i][0],t=ops[i][1],c=ops[i][2];
    	    trarr(s-1,L);trarr(t,R);
    		printf("%d
    ",fs[query(rt1[s-1],rt1[t],1,f,c)].val);
    	  }
    	  else
    	  {
    	    s=ops[i][0],t=ops[i][1];
    		int p=s;
    		for(;s<=n;s+=lowbit(s))
    		{
    		  insert(rt2[s],rt2[s],1,f,a[p],-1);
    		  insert(rt2[s],rt2[s],1,f,t,1);
    	    }
    		a[p]=t;
    	  }
    	}
      }
      
      return 0;
    }
    


  • 相关阅读:
    MATLAB 显示精度 用法设置以及实例
    matlab MCR路径
    fmincon如何使非线性约束函数写成匿名函数的形式
    Matlab强行终止程序执行
    Matlab绘制图像后在指定点绘制坐标线以及标注变量
    c#各种变量的总结
    Matlab绘制图像及图像的处理
    MATLAB 嵌套函数,子函数,私有函数,重载函数
    Matlab 接受字符串并转为符号表达式,inline函数,匿名函数形式的方法汇总
    MATLAB 函数编写方法, 浅析MATLAB中的内联函数、匿名函数和函数函数
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793806.html
Copyright © 2011-2022 走看看