文章目录
- 题意:
- 思路:
传送门
题意:
给你一个数组aaa,初始价值全为000,颜色全为111,让后让你实现以下三个操作:
- 将[l,r][l,r][l,r]区间内的颜色都染成ccc。
- 将所有颜色为ccc的位置价值都加上xxx。
- 询问iii位置的价值。
1≤n,q≤1e61\le n,q\le 1e61≤n,q≤1e6
思路:
首先分析一下第二个操作是全局的,这就提示我们每次执行第二个操作的时候可以打一个懒标记lazy[c]+=xlazy[c]+=xlazy[c]+=x,当询问某个点的价值的时候只需要输出ai+lazy[c]a_i+lazy[c]ai+lazy[c]即可,ccc为当前点的颜色。
但是这都是不考虑第一个操作的情况下的,考虑第一个操作,假设l==rl==rl==r,我们将他分为两个步骤:
- 首先将当前位置原本的颜色c′c'c′对应的lazy[c′]lazy[c']lazy[c′]加到ala_lal上。
- 将当前颜色改成ccc。
上述步骤很明显有一个问题,就是将修改前的lazy[c]lazy[c]lazy[c]的代价在第三个操作的时候也算进去了,这显然是不对的,不过我们发现可以在第二部中将al−lazy[c]a_l-lazy[c]al−lazy[c],这样就可以消除上述多余的价值了。
我们解决了单个的,再来看区间的怎么搞。
直接暴力不可以,但是我们不难发现可以将其拆分成若干个区间,每个区间的颜色都相同,类似与珂朵莉树,保证都是推平操作的话区间个数下降的很快的,这样我们只需要用setsetset维护这些区间,让后快速找到并且可以遍历这些区间修改他们,让后将他们推平,这看似暴力的算法实际平摊下来是O(q)O(q)O(q)的,由于对于每个区间我们还需要实现区间加某个数,显然BITBITBIT就可以实现,总复杂度是O(qlogn)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;
}