uva 12003 - Array Transformer(分块+树套树)

本文介绍了一种通过分块并结合排序与二分搜索来高效处理数组区间查询及单点更新的问题解决策略。适用于需要频繁进行元素查找与更新的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出数组A[1,2,...,n]和m条指令,每条指令形如(L,R,v,p)表示统计出A[L]...A[R]中严格小于v的有多少个,然后把A[p]修改成uk/(R-L+1)

思路:首先是分块,将数组分成sqrt(n)快,对每一块排序,询问的时候,对于两头的块,直接暴力,中间的,因为排好序了,所以直接二分就可以了,修改操作,用类似于插入排序的方法维护

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=4096;
const int maxm=300010;
int N,M,U;
int L,R,v,p;
int size;
int A[maxm];
int block[maxn][maxn];
int num;
void init()
{
    size=int(sqrt(N));
    for(int i=0;i<N;i++)scanf("%d",&A[i]);
    num=0;
    int j=0;
    for(int i=0;i<N;i++)
    {
        block[num][j]=A[i];
        if(++j==size){num++,j=0;}
    }
    for(int i=0;i<num;i++)sort(block[i],block[i]+size);
    if(j)sort(block[num],block[num]+j);
}
int Query(int l,int r,int v)
{
    int ans=0;
    int xpos=l/size,ypos=r/size;
    if(xpos==ypos)
    {
        for(int i=l;i<=r;i++)
            if(A[i]<v)ans++;
    }
    else
    {
        for(int i=l;i<(xpos+1)*size;i++)if(A[i]<v)ans++;
        for(int i=ypos*size;i<=r;i++)if(A[i]<v)ans++;
        for(int i=xpos+1;i<ypos;i++)
            ans+=lower_bound(block[i],block[i]+size,v)-block[i];
    }
    return ans;
}
void Change(int p,int x)
{
    if(A[p]==x)return;
    int bpos=p/size;
    int pos=0;
    int old=A[p];
    A[p]=x;
    while(block[bpos][pos]<old)pos++;
    block[bpos][pos]=x;
    if(x<=old)
        while(pos>0&&block[bpos][pos]<block[bpos][pos-1])
            swap(block[bpos][pos],block[bpos][pos-1]),pos--;
    else
        while(pos<size-1&&block[bpos][pos]>block[bpos][pos+1])
            swap(block[bpos][pos],block[bpos][pos+1]),pos++;
}
int main()
{
    while(scanf("%d%d%d",&N,&M,&U)!=EOF)
    {
        init();
        while(M--)
        {
            scanf("%d%d%d%d",&L,&R,&v,&p);
            L--,R--,p--;
            int k=Query(L,R,v);
            Change(p,(LL)U*k/(R-L+1));
        }
        for(int i=0;i<N;i++)printf("%d\n",A[i]);
    }
    return 0;
}

树套树TLE了,空间开太大。。。

#include<bits/stdc++.h>
using namespace std;
const int maxn=300010;
int A[maxn];
int N,M,U;
int L,R,v,p;
int tot;

struct Node
{
    int ch[2];
    int r;//优先级
    int v;//值
    int s;
    int cnt;//自身重复次数
    void init(int val){v=val;ch[0]=ch[1]=0;s=cnt=1;r=rand();}
    int cmp(int x)const
    {
        if(x==v)return -1;
        return x<v?0:1;
    }

}tree[maxn*15];
void maintain(int x)
{
    tree[x].s=tree[x].cnt;
    tree[x].s+=tree[tree[x].ch[0]].s+tree[tree[x].ch[1]].s;
}
void rotate(int &o,int d)
{
    int k=tree[o].ch[d^1];
    tree[o].ch[d^1]=tree[k].ch[d];
    tree[k].ch[d]=o;
    maintain(o);
    maintain(k);
    o=k;
}
void insert(int &o,int x)
{
    if(!o)
    {
        o=++tot;
        tree[o].init(x);
    }
    else
    {
        if(x==tree[o].v)tree[o].cnt++;
        else
        {
            int d=(x<tree[o].v?0:1);
            insert(tree[o].ch[d],x);
            if(tree[tree[o].ch[d]].r>tree[o].r)
                rotate(o,d^1);
        }
    }
    maintain(o);
}
void remove(int &o,int x)
{
    if(!o)return;
    int d=tree[o].cmp(x);
    if(d==-1)
    {
        int u=o;
        if(tree[o].cnt>1)tree[o].cnt--;
        else if(tree[o].ch[0]&&tree[o].ch[1])
        {
            int d2=(tree[tree[o].ch[0]].r>tree[tree[o].ch[1]].r?1:0);
            rotate(o,d2);
            remove(tree[o].ch[d2],x);
        }
        else
        {
            if(!tree[o].ch[0])o=tree[o].ch[1];
            else o=tree[o].ch[0];
            tree[u]=tree[0];
        }
    }
    else remove(tree[o].ch[d],x);
    if(o)maintain(o);
}
//返回最大值
int get_max(int o)
{
    while(tree[o].ch[0])o=tree[o].ch[0];
    return tree[o].v;
}
//返回最小值
int get_min(int o)
{
    while(tree[o].ch[1])o=tree[o].ch[1];
    return tree[o].v;
}
//返回val的前驱,如果没有的话返回y
//y的初值可赋成0,表示没有前驱
int get_pred(int o,int val,int y)
{
    if(!o)return y;
    if(tree[o].v<=val)//注意大于等于号
        return get_pred(tree[o].ch[1],val,tree[o].v);
    else return get_pred(tree[o].ch[0],val,y);
}
//返回val的后继,如果没有的话返回y
//y的初值可赋成0,表示没有后继
int get_succ(int o,int val,int y)
{
    if(!o)return y;
    if(tree[o].v>=val)return get_succ(tree[o].ch[0],val,tree[o].v);
    else return get_succ(tree[o].ch[1],val,y);
}
//返回第k大的元素的值
int get_kth(int o,int k)
{
    if(!o)return 0;
    if(k<=tree[tree[o].ch[0]].s)return get_kth(tree[o].ch[0],k);
    else if(k>tree[tree[o].ch[0]].s+tree[o].cnt)
        return get_kth(tree[o].ch[1],k-tree[tree[o].ch[0]].s-tree[o].cnt);
    return tree[o].v;
}
//返回val的排名
int get_rank(int o,int val)
{
    if(!o)return 0;
    int lsize=tree[tree[o].ch[0]].s;
    if(val<tree[o].v)
        return get_rank(tree[o].ch[0],val);
    else if(val>tree[o].v)
        return get_rank(tree[o].ch[1],val)+lsize+tree[o].cnt;
    return lsize;
}
struct IntervalTree
{
    int root[maxn<<2];
    void build(int o,int l,int r)
    {
        for(int i=l;i<=r;i++)
            insert(root[o],A[i]);
        if(l==r)return ;
        int mid=(l+r)>>1;
        build(o<<1,l,mid);
        build(o<<1|1,mid+1,r);
    }
    void update(int o,int l,int r,int pos,int val)
    {
        remove(root[o],A[pos]);
        insert(root[o],val);
        if(l==r)return ;
        int mid=(l+r)>>1;
        if(pos<=mid)update(o<<1,l,mid,pos,val);
        else update(o<<1|1,mid+1,r,pos,val);
    }
    int query(int o,int l,int r,int q1,int q2,int val)
    {
        if(l>r)return 0;
        if(q1<=l&&r<=q2)return get_rank(root[o],val);
        int mid=(l+r)>>1;//cout<<mid<<endl;
        int ans=0;
        if(q1<=mid)ans+=query(o<<1,l,mid,q1,q2,val);
        if(q2>mid)ans+=query(o<<1|1,mid+1,r,q1,q2,val);
        return ans;
    }
}tr;
void init()
{
    tot=0;
    memset(tr.root,0,sizeof(tr.root));
}
int main()
{
    while(scanf("%d%d%d",&N,&M,&U)!=EOF)
    {
        for(int i=1;i<=N;i++)scanf("%d",&A[i]);
        init();
        tr.build(1,1,N);
        while(M--)
        {
            scanf("%d%d%d%d",&L,&R,&v,&p);
            int ans=tr.query(1,1,N,L,R,v);
            //printf("%d\n",ans);
            tr.update(1,1,N,p,(long long)U*ans/(R-L+1));
            A[p]=v;
        }
        for(int i=1;i<=N;i++)printf("%d\n",A[i]);
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值