【BZOJ2883】gss2加强版

本文介绍了一种处理大规模数据集的高效算法,该算法能够快速完成数据查询与更新操作,并详细解释了其实现原理和步骤。

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

Description

给你N个数,你需要支持一下两种操作。
U x y,讲第x个数修改成y;
Q x y,计算从第x个数至第y个数中不同数的和并输出。如对于一段数{1,2,3,2,7},它的值是13(1+2+3+7)。
Input

第一行N表示数的个数(1<=N<=100000);
第二行包含这N个数;
第三行M表示操作次数(1<=N<=100000);
接下来M行每行三个数表示题目描述的操作。
所有的输入均在int以内。
Output

对于每个Q操作返回一个值。
Sample Input

5

1 2 4 2 3

3

Q 2 4

U 4 7

Q 2 4

Sample Output

6

13

HINT

【数据规模和约定】

30%:N<=3000,M<=3000

100%:N<=100000,M<=100000。

Source

把询问离散.
考虑对每个数维护上一次出现的位置,相同数值的数把这些位置丢进set.
所以对于修改用set改前驱后继搞一搞.
一个询问[l,r],其实就是问[l,r]内有多少数上一次出现的位置小于l,显然可以树套树做.
我本来以为线段树套动态开点权值线段树比平衡树常数小,没想到我的做法比Claris的线段树套平衡树慢那么多QAQ

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<set>
#include<algorithm>
#define MAXN 100010
#define SIZE 6000010
#define LL long long
#define GET (ch>='0'&&ch<='9')
#define ln rt<<1
#define rn rt<<1|1
using namespace std;
int n,m,cnt;
int pre[MAXN*2],a[MAXN],sta[MAXN*2],top;
struct query    {   int opt,x,y;    }q[MAXN];
int root[MAXN<<2];
LL sum[SIZE];
int ls[SIZE],rs[SIZE];
set<int> S[MAXN*3];
inline void in(int &x)
{
    char ch=getchar();x=0;
    while (!GET)    ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();
}
void Modify(int &rt,int l,int r,int x,int val)//modify in dynamic segment tree
{
    if (!rt)    rt=++cnt;
    if (l==r)   {   sum[rt]+=val;return;    }
    int mid=(l+r)>>1;
    if (x<=mid) Modify(ls[rt],l,mid,x,val);
    else    Modify(rs[rt],mid+1,r,x,val);
    sum[rt]=sum[ls[rt]]+sum[rs[rt]];
}
void modify(int rt,int l,int r,int x1,int x2,int val)//modify in ordinary segment tree
{
    Modify(root[rt],0,top,x2,val);
    if (l==r)   return;
    int mid=(l+r)>>1;
    if (x1<=mid)    modify(ln,l,mid,x1,x2,val);
    else    modify(rn,mid+1,r,x1,x2,val);
}
LL Query(int rt,int L,int R,int l,int r)//query in dynamic segment tree
{
    if (!rt)    return 0;
    if (L>=l&&R<=r) return sum[rt];
    int mid=(L+R)>>1;LL ret=0;
    if (l<=mid) ret+=Query(ls[rt],L,mid,l,r);
    if (r>mid)  ret+=Query(rs[rt],mid+1,R,l,r);
    return  ret;
}
LL query(int rt,int L,int R,int l,int r)//query in ordinary segment tree
{
    if (L>=l&&R<=r) return Query(root[rt],0,top,0,l-1);
    int mid=(L+R)>>1;LL ret=0;
    if (l<=mid) ret+=query(ln,L,mid,l,r);
    if (r>mid)  ret+=query(rn,mid+1,R,l,r);
    return ret;
}
int main()
{
    in(n);char ch[2];int x,y,prev;
    for (int i=1;i<=n;i++)  in(a[i]),sta[++top]=a[i];
    in(m);
    for (int i=1;i<=m;i++)
    {
        scanf("%s",ch);in(q[i].x);in(q[i].y);
        if (ch[0]=='Q') q[i].opt=0;
        else    q[i].opt=1,sta[++top]=q[i].y;
    }
    sort(sta+1,sta+top+1);top=unique(sta+1,sta+top+1)-sta;
    for (int i=1;i<=n;i++)
    {
        int val=lower_bound(sta+1,sta+top+1,a[i])-sta;
        modify(1,0,n,i,pre[val],a[i]);pre[val]=i;S[val].insert(i);
    }
    for (int i=1;i<=m;i++)
    {
        if (!q[i].opt)  printf("%lld\n",query(1,0,n,q[i].x,q[i].y));
        else
        {
            x=lower_bound(sta+1,sta+top+1,a[q[i].x])-sta;
            y=lower_bound(sta+1,sta+top+1,q[i].y)-sta;
            set<int>::iterator it=S[x].lower_bound(q[i].x);prev=0;
            if (it!=S[x].begin())   --it,prev=*it,++it;
            modify(1,0,n,q[i].x,prev,-a[q[i].x]);
            if ((++it)!=S[x].end()) modify(1,0,n,*it,q[i].x,-a[*it]),modify(1,0,n,*it,prev,a[*it]);
            --it;S[x].erase(it);prev=0;
            a[q[i].x]=q[i].y;S[y].insert(q[i].x);it=S[y].lower_bound(q[i].x);
            if (it!=S[y].begin())   --it,prev=*it,++it;
            modify(1,0,n,q[i].x,prev,a[q[i].x]);
            if ((++it)!=S[y].end()) modify(1,0,n,*it,prev,-a[*it]),modify(1,0,n,*it,q[i].x,a[*it]);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值