【BZOJ2883】gss2加强版

来源:互联网 发布:快思聪中控编程教程 编辑:程序博客网 时间:2024/05/01 12:43

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|1using 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]);        }    }}
1 0
原创粉丝点击