刷题总结——序列操作(权值线段树套树状数组)

题目:

题目描述

给出序列 a1,a2,…,an(0≤ai≤109),有关序列的两种操作。

1. ai(1≤i≤n)变成 x(0≤x≤109)。

2. 求 al,al+1,…,ar(1≤l≤r≤n)第 k(1≤k≤r-l+1)小。

输入格式

第一行包含两个数 n(1≤n≤2×104)和 m(1≤m≤2×104),表示序列长度和操作次数。

接下来一行 n 个数,以空格隔开,表示 a1,a2,…,an 。

接下来m行,每行为以下两种格式之一:

  • 0 i x ,  表示 ai=x。
  • 1 l r k ,求 al,al+1,…,ar 的第 k 小。

输出格式

对于每次询问,输出单独的一行表示答案。

样例数据 1

输入  [复制]

 
5 3 
1 2 3 4 5 
1 1 5 3 
0 3 5 
1 1 5 3

输出


4

题解:

  待修改的权值线段树的模板题

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;

int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

const int N=2e4+5,M=2e6+5;
struct node
{
    int op,x,y,k;
}q[N];
struct tree
{
    int lc,rc,size;
}tr[M];
int n,m,len,tot,a[N],b[N<<1],bit[N],pos[N];

void dic_init()
{
    sort(b+1,b+len+1);
    len=unique(b+1,b+len+1)-b-1;
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(b+1,b+len+1,a[i])-b;
    for(int i=1;i<=m;i++)
        if(!q[i].op)
            q[i].y=lower_bound(b+1,b+len+1,q[i].y)-b;
}

void Insert(int &k,int l,int r,int x)
{
    if(!k)k=++tot;
    tr[k].size++;
    if(l==r)return;
    int mid=l+r>>1;
    if(x<=mid)Insert(tr[k].lc,l,mid,x);
    else Insert(tr[k].rc,mid+1,r,x);
}

void Add(int x)
{
    for(int i=x;i<=n;i+=i&(-i))
        Insert(bit[i],1,len,a[x]);
}

void Delete(int k,int l,int r,int x)
{
    tr[k].size--;
    if(l==r)return;
    int mid=l+r>>1;
    if(x<=mid)Delete(tr[k].lc,l,mid,x);
    else Delete(tr[k].rc,mid+1,r,x);
}

void Rec(int x)
{
    for(int i=x;i<=n;i+=i&(-i))
        Delete(bit[i],1,len,a[x]);
}

void pre(int x,int y)
{
    for(int i=x;i>0;i-=i&(-i))
        pos[i]=bit[i];
    for(int i=y;i>0;i-=i&(-i))
        pos[i]=bit[i];
}

int calc(int x,int y)
{
    int res=0;
    for(int i=x;i>0;i-=i&(-i))
        res+=tr[tr[pos[i]].lc].size;
    for(int i=y;i>0;i-=i&(-i))
        res-=tr[tr[pos[i]].lc].size;
    return res;
}

void trans(int x,int y,int f)
{
    for(int i=x;i>0;i-=i&(-i))
        if(!f)pos[i]=tr[pos[i]].lc;
        else pos[i]=tr[pos[i]].rc;
    for(int i=y;i>0;i-=i&(-i))
        if(!f)pos[i]=tr[pos[i]].lc;
        else pos[i]=tr[pos[i]].rc;
}

int query(int rt1,int rt2,int l,int r,int k)
{
    if(l==r)return l;
    int delta=calc(rt1,rt2);
    int mid=l+r>>1;
    if(delta>=k)
    {
        trans(rt1,rt2,0);
        return query(rt1,rt2,l,mid,k);
    }
    else 
    {
        trans(rt1,rt2,1);
        return query(rt1,rt2,mid+1,r,k-delta);
    }
}

int main()
{
    //freopen("a.in","r",stdin);
    n=getint(),m=getint();
    for(int i=1;i<=n;i++)
        a[i]=getint(),b[++len]=a[i];
    for(int i=1;i<=m;i++)
    {
        q[i].op=getint();
        q[i].x=getint();
        q[i].y=getint();
        if(!q[i].op)b[++len]=q[i].y;
        else q[i].k=getint();
    }    
    
    dic_init();
    for(int i=1;i<=n;i++)Add(i);
    
    for(int i=1;i<=m;i++)
        if(!q[i].op)
        {
            Rec(q[i].x);
            a[q[i].x]=q[i].y;
            Add(q[i].x);
        }
        else
        {
            pre(q[i].y,q[i].x-1);
            cout<<b[query(q[i].y,q[i].x-1,1,len,q[i].k)]<<'
';
        }
    return 0;
}
原文地址:https://www.cnblogs.com/AseanA/p/7201294.html