CF877F 题解

1|0CF877F 题解

更好的阅读体验


提供一个扫描线 + 根号分治做法。

首先,可以把题目的条件转化成求 sumrsuml1=k 的区间数。

考虑扫描线,当区间的右端点从 r1 移动到 r 时,新增的区间的左端点就是所有满足 suml1=sumrk,lrl。这时我们对 suml1 的出现次数按 B 进行分治。

具体的,如果出现次数 B ,那么我们这一次至多会修改 B 个位置,而查询只有一次,于是可以采用 O(1)O(n) 的分块来维护;如果出现次数 >B,这样的数至多有 nB 个,我们可以对每个数都维护一个数据结构,要求支持区间加以及区间和,而每次加的操作只有 O(1) 次,但是每个询问都要对每个数进行查询,共 nB 次,于是可以采用 O(n)O(1)  的分块(具体可见

LOJ#6280. 数列分块入门 4)


总复杂度 O(nn+qn+nB+qnB)Bn 时就可以在 O(nn+qn) 的复杂度内解决这道题。

 

1 const int N=100501,B=1000; 2 int n,k,Q; 3 int t[N],a[N],tot,bl[N],L[N],R[N]; 4 ll pre[N],ans[N],st[N]; 5 vector<pair<int,int> >qu[N]; 6 map<ll,int>mp; 7 struct Brick{ 8 ll sum[N],sumb[N]; 9 inline void modify(int x){sum[x]++,sumb[bl[x]]++;} 10 inline ll query(int l,int r){ 11 if(bl[l]==bl[r]){ 12 ll ans=0; 13 for(int i=l;i<=r;i++)ans+=sum[i]; 14 return ans; 15 } 16 ll ans=0; 17 for(int i=l;i<=R[bl[l]];i++)ans+=sum[i]; 18 for(int i=bl[l]+1;i<bl[r];i++)ans+=sumb[i]; 19 for(int i=L[bl[r]];i<=r;i++)ans+=sum[i]; 20 return ans; 21 } 22 }T; 23 vector<int>hav[N],big; 24 int id[N],cnt; 25 struct Bri{ 26 vector<ll>pre,sum,tag; 27 int n; 28 inline void init(int m){n=m;pre.resize(n+1),sum.resize(n+1),tag.resize(n+1);} 29 inline void add(int x,int k){ 30 for(int i=x;i<=R[bl[x]];i++)pre[i]+=1ll*k*(i-x+1); 31 for(int i=bl[x]+1;i<=bl[n];i++)sum[i]+=1ll*k*(1-x),tag[i]+=k; 32 } 33 inline void add(int l,int r,int k){add(l,k);if(r<n)add(r+1,-k);} 34 inline ll query(int x){return pre[x]+sum[bl[x]]+1ll*tag[bl[x]]*x;} 35 inline ll query(int l,int r){return query(r)-query(l-1);} 36 }b[N/B+50]; 37 int low[N/B+50][N],upp[N/B+50][N]; 38 int main(){ 39 n=read(),k=read(); 40 for(int i=1;i<=n;i++)t[i]=read(); 41 for(int i=1;i<=n;i++)a[i]=read(),pre[i]=pre[i-1]+(t[i]==1?a[i]:-a[i]); 42 for(int i=0;i<n;i++)st[++tot]=pre[i]; 43 sort(st+1,st+tot+1); 44 tot=unique(st+1,st+tot+1)-st-1; 45 for(int i=1;i<=tot;i++)mp[st[i]]=i; 46 for(int i=0;i<n;i++)hav[mp[pre[i]]].push_back(i); 47 for(int i=1;i<=n;i++){ 48 bl[i]=(i-1)/B+1; 49 if(bl[i]^bl[i-1])L[bl[i]]=i; 50 R[bl[i]]=i; 51 } 52 for(int i=1;i<=tot;i++)if((int)hav[i].size()>B)big.push_back(i),id[i]=++cnt; 53 for(int i=0;i<n;i++)if(id[mp[pre[i]]]){ 54 int x=id[mp[pre[i]]]; 55 low[x][i+1]++; 56 upp[x][i+2]++; 57 } 58 for(int i=1;i<=cnt;i++){ 59 upp[i][0]=1; 60 for(int j=1;j<=n;j++)low[i][j]+=low[i][j-1],upp[i][j]+=upp[i][j-1]; 61 b[i].init(low[i][n]); 62 } 63 Q=read(); 64 for(int t=1;t<=Q;t++){ 65 int l=read(),r=read(); 66 qu[r].push_back({l,t}); 67 } 68 for(int i=1;i<=n;i++){ 69 ll cur=pre[i]-k; 70 if(mp[cur]){ 71 int x=mp[cur]; 72 int len=hav[x].size(); 73 if(len<=B){ 74 for(auto j:hav[x]){ 75 if(j>=i)break; 76 T.modify(j+1); 77 } 78 } 79 else{ 80 int y=id[x]; 81 b[y].add(1,low[y][i],1); 82 } 83 } 84 for(auto j:qu[i]){ 85 int l=j.first,id=j.second; 86 ans[id]+=T.query(l,i); 87 for(int k=1;k<=cnt;k++)ans[id]+=b[k].query(upp[k][l],low[k][i]); 88 } 89 } 90 for(int i=1;i<=Q;i++)write(ans[i]),putchar('\n'); 91 return 0; 92 }

 


__EOF__

本文作者Xttttr
本文链接https://www.cnblogs.com/Xttttr/p/17725161.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Xttttr  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示