BZOJ 3343 魔法
我们注意到q很小,每次询问的区间最多被之前的修改划分成O(q)个区间,我们把每个区间放到主席树上查询。
#pragma GCC optimize("-Ofast") #include<bits/stdc++.h> #define fi first #define se second #define N 11000007//||| #define Q 6007 #define Max(a,b) (a>b?a:b) #define Min(a,b) (a<b?a:b) #define Mid (l+r>>1) using namespace std; int n,q,x,ls[N],rs[N],key[N],rt[N/10],cnt,l[Q],r[Q],w[Q],L,R,tot,C,ans; long long sum; char ch[4]; map<int,int> mp; map<int,int>:: iterator it,la; void add(int last,int &now,int l,int r,int pos){ now=++cnt; key[now]=key[last]+1; if (l==r) return; if (pos<=Mid) rs[now]=rs[last],add(ls[last],ls[now],l,Mid,pos); else ls[now]=ls[last],add(rs[last],rs[now],Mid+1,r,pos); } int que(int now,int l,int r,int pos){ if (l==r) return key[now]; if (pos<=Mid) return key[rs[now]]+que(ls[now],l,Mid,pos); return que(rs[now],Mid+1,r,pos); } inline void read(int &x){ static char c; for (c=getchar();!isdigit(c);c=getchar()); for (x=0;isdigit(c);c=getchar())x=x*10+c-48; } void write(int x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);} inline void writeln(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); } inline void writel(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); } signed main () { // cerr<<(sizeof ls*3)<<endl; read(n); read(q); for (int i=1;i<=n;i++) read(x), add(rt[i-1],rt[i],1,1000,x); for (int i=1;i<=q;i++) { scanf("%s",ch); if (ch[0]=='M') { read(l[++tot]); read(r[tot]); read(w[tot]); } else { ans=0; read(L); read(R); read(C); mp[L-1]=C; mp[R]=-C; for (int j=1;j<=tot;j++) { if (r[j]<L||l[j]>R) continue; mp[Max(L,l[j])-1]-=w[j]; mp[Min(R,r[j])]+=w[j]; } sum=0; for (it=mp.begin(),la=mp.begin();it!=mp.end();it++) { if (it!=mp.begin()) { if (sum>1000) {la++; continue;} ans+=que(rt[it->fi],1,1000,Max(sum,1)); ans-=que(rt[la->fi],1,1000,Max(sum,1)); la++; } sum+=it->se; } mp.clear();printf("%d\n",ans); } } }