1. 程式人生 > >洛谷3380 二逼平衡樹(樹套樹)

洛谷3380 二逼平衡樹(樹套樹)

close div print 輸出 輸出格式 -c 一個 ans 求和

題目描述

您需要寫一種數據結構(可參考題目標題),來維護一個有序數列,其中需要提供以下操作:

  1. 查詢k在區間內的排名

  2. 查詢區間內排名為k的值

  3. 修改某一位值上的數值

  4. 查詢k在區間內的前驅(前驅定義為嚴格小於x,且最大的數,若不存在輸出-2147483647)

  5. 查詢k在區間內的後繼(後繼定義為嚴格大於x,且最小的數,若不存在輸出2147483647)

註意上面兩條要求和tyvj或者bzoj不一樣,請註意

輸入輸出格式

輸入格式:

第一行兩個數 n,m 表示長度為n的有序序列和m個操作

第二行有n個數,表示有序序列

下面有m行,opt表示操作標號

若opt=1 則為操作1,之後有三個數l,r,k 表示查詢k在區間[l,r]的排名

若opt=2 則為操作2,之後有三個數l,r,k 表示查詢區間[l,r]內排名為k的數

若opt=3 則為操作3,之後有兩個數pos,k 表示將pos位置的數修改為k

若opt=4 則為操作4,之後有三個數l,r,k 表示查詢區間[l,r]內k的前驅

若opt=5 則為操作5,之後有三個數l,r,k 表示查詢區間[l,r]內k的後繼

輸出格式:

對於操作1,2,4,5各輸出一行,表示查詢結果

輸入輸出樣例

輸入樣例#1: 復制
9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5
輸出樣例#1: 復制
2
4
3
4
9

說明

時空限制:2s,128M

n,m≤5⋅104 n,m \leq 5\cdot {10}^4 n,m5104 保證有序序列所有值在任何時刻滿足 [0,108] [0, {10} ^8] [0,108]

題目來源:bzoj3196 / Tyvj1730 二逼平衡樹,在此鳴謝

此數據為洛谷原創。(特別提醒:此數據不保證操作5、6一定存在,故請務必考慮不存在的情況

一直覺得樹套樹好難好難的,寫了一下,覺得還好,(●‘?‘●)

#include<bits/stdc++.h>
#define lb(x) (-x&x)
#define nn 500011
using namespace std;
const int inf=1e8;
int ls[nn*97],rs[nn*97],sum[nn*97];
int rot[nn],a[nn],ql[nn],qr[nn];
int li,nod,n;
int read()
{
    int ans=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();}
    while(isdigit(ch)) {ans=ans*10+ch-‘0‘;ch=getchar();}
    return ans*f;
}
void amend(int &rt,int l,int r,int v,int nv)
{
    if(!rt) rt=++nod;
    sum[rt]+=nv;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(v<=mid) amend(ls[rt],l,mid,v,nv);
    else amend(rs[rt],mid+1,r,v,nv);
}
void modify(int p,int v,int nv)
{
    for(int i=p;i<=n;i+=lb(i))
      amend(rot[i],0,inf,v,nv);
}
int getnum(int rt,int l,int r,int x)
{
    if(!rt) return 0;
    if(l==r) return sum[rt];
    int mid=(l+r)>>1;
    if(x<=mid)
      return getnum(ls[rt],l,mid,x);
    else
      return sum[ls[rt]]+getnum(rs[rt],mid+1,r,x);
}
int rank(int l,int r,int x)        //l,r裏查詢x的排名 
{
    int num=0;l--;
    for(int i=r;i>=1;i-=lb(i))
      num+=getnum(rot[i],0,inf,x-1);
    for(int i=l;i>=1;i-=lb(i))
      num-=getnum(rot[i],0,inf,x-1);
    return num+1;
}
int findk(int l,int r,int k)         //l,r裏查詢排名為k的
{
    int h1=1,t1=0,tt1,h2=1,t2=0,tt2,lv=0,rv=inf,num;l--;
    for(int i=l;i>=1;i-=lb(i))
      if(rot[i]&&sum[rot[i]])
        ql[++t1]=rot[i];
    for(int i=r;i>=1;i-=lb(i))
      if(rot[i]&&sum[rot[i]])
        qr[++t2]=rot[i];
    while(lv!=rv)
    {
        num=0;
        for(int i=h1;i<=t1;i++)
          num-=sum[ls[ql[i]]];
        for(int i=h2;i<=t2;i++)
          num+=sum[ls[qr[i]]];
        tt1=t1,tt2=t2;
        while(h1<=tt1)
        {
            if(num>=k)
            {
                ql[++t1]=ls[ql[h1++]];
                if(!ql[t1]||!sum[ql[t1]]) t1--;
            }
            else
            {
                ql[++t1]=rs[ql[h1++]];
                 if(!ql[t1]||!sum[ql[t1]]) t1--;
            }
        }
        while(h2<=tt2)
        {
            if(num>=k)
            {
                qr[++t2]=ls[qr[h2++]];
                if(!qr[t2]||!sum[qr[t2]]) t2--;
            }
            else
            {
                qr[++t2]=rs[qr[h2++]];
                if(!qr[t2]||!sum[qr[t2]]) t2--;
            }
        }
        if(num>=k)
          rv=(lv+rv)>>1;
        else
          lv=((lv+rv)>>1)+1,k-=num;
    }
    return rv;
}
int pre(int l,int r,int x)
{
    int k=rank(l,r,x)-1;
    if(k<=0)
      return -2147483647;
    return findk(l,r,k);
}
int sub(int l,int r,int x)
{
    int k=rank(l,r,x+1)-1;
    if(k==r-l+1)
      return 2147483647;
    int ans=findk(l,r,k+1);
    return ans;
}
int main()
{
    int m,opt,x,l,r;
    n=read();m=read();
    for(int i=1;i<=n;i++)
      a[i]=read(),modify(i,a[i],1);
    for(int i=1;i<=m;i++)
    {
        opt=read();l=read();r=read();
        if(opt==1)
          x=read(),printf("%d\n",rank(l,r,x));
        if(opt==2)
          x=read(),printf("%d\n",findk(l,r,x));
        if(opt==3)
          modify(l,a[l],-1),modify(l,a[l]=r,1);
        if(opt==4)
          x=read(),printf("%d\n",pre(l,r,x));
        if(opt==5)
          x=read(),printf("%d\n",sub(l,r,x));
    }
    return 0;
}

洛谷3380 二逼平衡樹(樹套樹)