题意:
给你一个数组 a a a,初始价值全为 0 0 0,颜色全为 1 1 1,让后让你实现以下三个操作:
- 将 [ l , r ] [l,r] [l,r]区间内的颜色都染成 c c c。
- 将所有颜色为 c c c的位置价值都加上 x x x。
- 询问 i i i位置的价值。
1 ≤ n , q ≤ 1 e 6 1\le n,q\le 1e6 1≤n,q≤1e6
思路:
首先分析一下第二个操作是全局的,这就提示我们每次执行第二个操作的时候可以打一个懒标记 l a z y [ c ] + = x lazy[c]+=x lazy[c]+=x,当询问某个点的价值的时候只需要输出 a i + l a z y [ c ] a_i+lazy[c] ai+lazy[c]即可, c c c为当前点的颜色。
但是这都是不考虑第一个操作的情况下的,考虑第一个操作,假设 l = = r l==r l==r,我们将他分为两个步骤:
- 首先将当前位置原本的颜色 c ′ c' c′对应的 l a z y [ c ′ ] lazy[c'] lazy[c′]加到 a l a_l al上。
- 将当前颜色改成 c c c。
上述步骤很明显有一个问题,就是将修改前的 l a z y [ c ] lazy[c] lazy[c]的代价在第三个操作的时候也算进去了,这显然是不对的,不过我们发现可以在第二部中将 a l − l a z y [ c ] a_l-lazy[c] al−lazy[c],这样就可以消除上述多余的价值了。
我们解决了单个的,再来看区间的怎么搞。
直接暴力不可以,但是我们不难发现可以将其拆分成若干个区间,每个区间的颜色都相同,类似与珂朵莉树,保证都是推平操作的话区间个数下降的很快的,这样我们只需要用 s e t set set维护这些区间,让后快速找到并且可以遍历这些区间修改他们,让后将他们推平,这看似暴力的算法实际平摊下来是 O ( q ) O(q) O(q)的,由于对于每个区间我们还需要实现区间加某个数,显然 B I T BIT BIT就可以实现,总复杂度是 O ( q l o g n ) O(qlogn) O(qlogn)。
#include<bits/stdc++.h>
#define Mid (tr[u].l+tr[u].r>>1)
#define pb push_back
#define IT set<node>::iterator
#define x first
#define y second
using namespace std;
const int N=2000010,INF=0x3f3f3f3f,mod=1e9+7;
typedef long long LL;
typedef pair<LL,LL> PII;
int n,m;
LL a[N];
vector<PII>v[N];
struct node
{
int l,r,t;
mutable int v;
bool operator < (const node& o) const {
return l<o.l;
}
};
set<node>s;
int find(int col,int t) {
int l=0,r=(int)v[col].size()-1,ans=-1;
if(r==-1) return INF;
while(l<=r) {
int mid=l+r>>1;
if(v[col][mid].y<t) ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
struct BIT {
LL tr[N];
#define lowbit(x) (x&(-x))
void add(int x,LL c) {
for(int i=x;i<N;i+=lowbit(i)) tr[i]+=c;
}
LL sum(int x) {
LL ans=0;
for(int i=x;i;i-=lowbit(i)) ans+=tr[i];
return ans;
}
}bit;
IT splitl(int pos) {
IT it=s.upper_bound({pos,-1,-1,-1});
--it;
return it;
}
IT splitr(int pos) {
IT it=s.upper_bound({pos,-1,-1,-1});
return it;
}
void add(int l,int r,int c,int t) {
IT itr=splitr(r+1);
IT itl=splitl(l);
for(;itl!=itr;++itl) {
int ls=itl->l,rs=itl->r;
ls=max(ls,l);
rs=min(rs,r);
int col=itl->v,t=itl->t;
int pos=find(col,t);
if(pos!=INF) {
LL ed=v[col].back().x;
if(pos!=-1) ed-=v[col][pos].x;
bit.add(rs+1,-ed); bit.add(ls,ed);
}
}
itl=splitl(l);
node ls,rs;
ls.l=-1; rs.l=-1;
if(itl->l<l) {
ls.l=itl->l; ls.r=l-1;
ls.v=itl->v; ls.t=itl->t;
}
if(itl->r>r) {
rs.l=r+1; rs.r=itl->r;
rs.v=itl->v; rs.t=itl->t;
}
itr--;
if(itr->r>r) {
rs.l=r+1; rs.r=itr->r;
rs.v=itr->v; rs.t=itr->t;
}
itr++;
s.erase(itl,itr);
if(ls.l!=-1) s.insert(ls);
if(rs.l!=-1) s.insert(rs);
s.insert({l,r,t,c});
}
LL query(int pos) {
IT now=splitl(pos);
int t=now->t,col=now->v;
pos=find(col,t);
LL ans=0;
if(pos!=INF) {
LL ed=v[col].back().x;
if(pos!=-1) ed-=v[col][pos].x;
ans+=ed;
}
return ans;
}
void solve() {
scanf("%d%d",&n,&m);
s.insert({1,n,0,1});
for(int i=1;i<=m;i++) {
char ss[10];
scanf("%s",ss+1);
if(ss[1]=='C') {
int l,r,c; scanf("%d%d%d",&l,&r,&c);
add(l,r,c,i);
} else if(ss[1]=='A') {
int c,x; scanf("%d%d",&c,&x);
if(v[c].size()) {
LL ed=v[c].back().x;
v[c].pb({x+ed,i});
}
else v[c].pb({x,i});
} else if(ss[1]=='Q') {
int x; scanf("%d",&x);
printf("%lld\n",bit.sum(x)+query(x));
}
}
}
int main() {
int _=1;
while(_--) {
solve();
}
return 0;
}