您的位置:首页 > 其它

【BZOJ2883】gss2加强版

2016-03-15 10:39 253 查看
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]);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: