【函数式权值分块】【分块】bzoj3196 Tyvj 1730 二逼平衡树

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define N 50001
#define SQRT 227
int n,m,xs[N],ys[N],ks[N],op[N],en,ma[100001],en2,a[100001];
int num[N],l[SQRT],r[SQRT],sumv[SQRT],sum=1;//分块
int num2[100001],l2[320],r2[320],tot=1;//函数式权值分块
struct Point{int v,p;}t[100001];
bool operator < (const Point &a,const Point &b){return a.v<b.v;}
struct Val_Block
{
    int b[100001],sumv[320];
    void Insert(const int &x){++b[x]; ++sumv[num2[x]];}
    void Delete(const int &x){--b[x]; --sumv[num2[x]];}
}T[SQRT],S;
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 sz=sqrt(en2);
	if(!sz) sz=1;
    for(;tot*sz<en2;++tot)
      {
        l2[tot]=r2[sum-1]+1;
		r2[tot]=tot*sz;
        for(int i=l2[tot];i<=r2[tot];++i)
		  num2[i]=tot;
      }
    l2[tot]=r2[sum-1]+1;
	r2[tot]=en2;
    for(int i=l2[tot];i<=r2[tot];++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 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;
}
int Rank(const int &L,const int &R,const int &x)
{
    int cnt=0;
    if(num[L]+1>=num[R])
      {
      	for(int i=L;i<=R;++i)
		  S.Insert(a[i]);
		for(int i=1;i<num2[x];i++)
		  cnt+=S.sumv[i];
    	for(int i=l2[num2[x]];i<x;i++)
		  cnt+=S.b[i];
		for(int i=L;i<=R;++i)
		  S.Delete(a[i]);
    	return cnt+1;
      }
    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<num2[x];i++)
	  cnt+=(T[RB].sumv[i]-T[LB].sumv[i]+S.sumv[i]);
    for(int i=l2[num2[x]];i<x;i++)
	  cnt+=(T[RB].b[i]-T[LB].b[i]+S.b[i]);
	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 cnt+1;
}
int 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;
}
void P(int x){
    if(x<10)putchar(x+‘0‘);
    else{P(x/10);putchar(x%10+‘0‘);}
}
int Next(const int &L,const int &R,const int &x)
{
	int res;
	if(num[L]+1>=num[R])
	  {
	  	for(int i=L;i<=R;++i)
		  S.Insert(a[i]);
	  	for(int i=x+1;i<=r2[num2[x]];i++)
	  	  if(S.b[i])
			{
			  res=i;
			  goto OUT2;
			}
    	for(int i=num2[x]+1;;i++)
	  	  if(S.sumv[i])
        	for(int j=l2[i];;j++)
          	  if(S.b[j])
          	    {
          	      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=x+1;i<=r2[num2[x]];i++)
	  if((T[RB].b[i]-T[LB].b[i]+S.b[i]))
		{
		  res=i;
		  goto OUT;
		}
    for(int i=num2[x]+1;;i++)
	  if((T[RB].sumv[i]-T[LB].sumv[i]+S.sumv[i]))
        for(int j=l2[i];;j++)
          if((T[RB].b[j]-T[LB].b[j]+S.b[j]))
          	{
          	    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;
}
int Pre(const int &L,const int &R,const int &x)
{
	int res;
	if(num[L]+1>=num[R])
	  {
	  	for(int i=L;i<=R;++i)
		  S.Insert(a[i]);
	  	for(int i=x-1;i>=l2[num2[x]];i--)
	  	  if(S.b[i])
			{
			  res=i;
			  goto OUT2;
			}
    	for(int i=num2[x]-1;;i--)
	  	  if(S.sumv[i])
        	for(int j=r2[i];;j--)
          	  if(S.b[j])
          	    {
          	      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=x-1;i>=l2[num2[x]];i--)
	  if((T[RB].b[i]-T[LB].b[i]+S.b[i]))
		{
		  res=i;
		  goto OUT;
		}
    for(int i=num2[x]-1;;i--)
	  if((T[RB].sumv[i]-T[LB].sumv[i]+S.sumv[i]))
        for(int j=r2[i];;j--)
          if((T[RB].b[j]-T[LB].b[j]+S.b[j]))
          	{
          	    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;
}
int main()
{
	R(n);
	R(m);
	makeblock();
	en=n;
	for(int i=1;i<=n;++i)
	  R(t[i].v),
	  t[i].p=i;
	for(int i=1;i<=m;++i)
	  {
	  	R(op[i]);
	  	if(op[i]==3)
	  	  R(xs[i]),R(ks[i]);
	  	else
		  R(xs[i]),R(ys[i]),R(ks[i]);
		if(op[i]!=2)
		  t[++en].v=ks[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]!=2)
		  ++en;
        if(op[i]==3)
          {
            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 if(op[i]==2)
		  P(ma[Kth(xs[i],ys[i],ks[i])]),puts("");
		else if(op[i]==1)
		  P(Rank(xs[i],ys[i],a[en])),puts("");
		else if(op[i]==4)
		  P(ma[Pre(xs[i],ys[i],a[en])]),puts("");
		else
		  P(ma[Next(xs[i],ys[i],a[en])]),puts("");
      }
	return 0;
}
时间: 2024-12-30 00:15:56

【函数式权值分块】【分块】bzoj3196 Tyvj 1730 二逼平衡树的相关文章

【带修莫队】【权值分块】bzoj3196 Tyvj 1730 二逼平衡树

这题用了三种算法写: 分块+二分:O(n*sqrt(n*log(n)) 函数式权值分块:O(n*sqrt(n)) 带修莫队+权值分块:O(n5/3) 结果……复杂度越高的实际上跑得越快……最后这个竟然进第一页了…… #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int f,C; inline void R(int &

【分块】bzoj3196 Tyvj 1730 二逼平衡树

分块 或 树套树. 在每个块中维护一个有序表,查询时各种二分,全都是分块的经典操作,就不详细说了. 块的大小定为sqrt(n*log2(n))比较快. 1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int sum,sz,l[400],r[400],num[51001],a[51001],b[5100

Bzoj3196 Tyvj 1730 二逼平衡树

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3350  Solved: 1324 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行

[bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)

Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作 第二行有n个数,表示有序序列 下面有m行,opt表示操作标号 若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间

【线段树套平衡树】【pb_ds】bzoj3196 Tyvj 1730 二逼平衡树

线段树套pb_ds里的平衡树,在洛谷OJ上测试,后三个测试点TLE #include<cstdio> #include<algorithm> #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/tree_policy.hpp> #define N 50010 #define INF 2147483647 using namespace std; using namespace __gnu_pb

【BZOJ 3196】Tyvj 1730 二逼平衡树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 842  Solved: 350 [Submit][Status] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,

bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,

BZOJ 3196: Tyvj 1730 二逼平衡树( 树套树 )

这道题做法应该很多吧.... 我用了线段树套treap.... -------------------------------------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> #include<ios

[Tyvj 1730] 二逼平衡树

先来一发题面QwQ [TYVJ1730]二逼平衡树 Time Limit:2 s   Memory Limit:512 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数