xsy2517. color

\(n\) 种颜色,第 \(i\) 种颜色的美丽值为 \(a_i\)。给定一根长度为 \(n\) 的颜色序列。一段区间的美丽值定义为出现的颜色的美丽值之和,如果一种颜色出现了多次,也只被计算一次。\(q\) 次操作,要支持单点修改颜色和区间询问美丽值,数据在线。
\(1\le n,q\le 10^5\)


小清新主席树题。

考虑对区间中出现多次的颜色在最先出现的位置计算它,那么最先出现的位置满足上一次出现该颜色的位置在询问左端点 \(l\) 的左侧。于是可以把第 \(i\) 个位置抽象成坐标系上的一个点 \((\text{last}_{\text{col}_i}+1,i)\),询问就是 \((1\sim l,l\sim r)\) 矩形的和。容易用树状数组套主席树实现。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
struct Node{int ls,rs;ll sum;}tr[N*100];
int n,m,cnt,c[N],w[N],rt[N];ll ans;set<int>s[N];
inline int lst(int c,int p){
    set<int>::iterator it=s[c].lower_bound(p);
    return *(--it);
}
inline int nxt(int c,int p){
    set<int>::iterator it=s[c].upper_bound(p);
    return it==s[c].end()?-1:*it;
}
inline void update(int &x,int l,int r,int y,int v){
    if(!x)x=++cnt;
    if(l==r)return void(tr[x].sum+=v);
    int mid=l+r>>1;
    y<=mid?update(tr[x].ls,l,mid,y,v):update(tr[x].rs,mid+1,r,y,v);
    tr[x].sum=tr[tr[x].ls].sum+tr[tr[x].rs].sum;
}
inline ll query(int x,int l,int r,int L,int R){
    if(L<=l&&R>=r)return tr[x].sum;
    int mid=l+r>>1;ll ans=0;
    if(L<=mid)ans=query(tr[x].ls,l,mid,L,R);
    if(R>mid)ans+=query(tr[x].rs,mid+1,r,L,R);
    return ans;
}
inline void add(int x,int y,int v){for(;x<=n;x+=x&-x)update(rt[x],1,n,y,v);}
inline ll ask(int x,int l,int r){ll ans=0;for(;x;x&=x-1)ans+=query(rt[x],1,n,l,r);return ans;}
inline void modify(int p,int o){
    int v=lst(c[p],p),u=nxt(c[p],p);
    add(v+1,p,-w[c[p]]);
    if(~u){
        add(p+1,u,-w[c[p]]);
        add(v+1,u,w[c[p]]);
    }
    s[c[p]].erase(p),c[p]=o;
    s[o].insert(p);
    v=lst(o,p),u=nxt(o,p);
    if(~u){
        add(v+1,u,-w[o]);
        add(p+1,u,w[o]);
    }
    add(v+1,p,w[o]);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d",c+i),s[i].insert(0),s[c[i]].insert(i);
    for(int i=1;i<=n;++i)scanf("%d",w+i);
    for(int i=1;i<=n;++i)add(lst(c[i],i)+1,i,w[c[i]]);
    while(m--){
        int type;ll l,r;scanf("%d%lld%lld",&type,&l,&r);
        if(type&1)modify(l^ans,r^ans);
        else printf("%lld\n",ans=ask(l^ans,l^ans,r^ans));
    }
    return 0;
}
posted @ 2022-06-11 17:47  Samsara-soul  阅读(47)  评论(0编辑  收藏  举报