漏网之鱼
Posted xjqxjq
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了漏网之鱼相关的知识,希望对你有一定的参考价值。
题目描述
给定一个 $n$ 个数的序列 $a$ ,有 $q$ 次询问,每次询问区间 $[l,r]$ 的所有子区间的 $mex$ 的和。
数据范围
$1 le n,Q le 10^6$ ; $0 le a_i le 10^9$
题解
考虑把 $[l,r]$ 的答案拆成起点在 $[1,r]$ ,终点在 $[l,r]$ 的答案减去起点在 $[1,l-1]$ 的答案。
考虑离线,考虑推动l指针,线段树上端点 $r$ 维护 $[l,r]$ 的 $mex$ 及历史信息。考虑 $l$ 到 $l+1$ 的时候的贡献,画个图会发现它会把一段区间改成 $a_l$ 。
现在考虑终点在 $r$ ,如何维护起点在 $[1,l]$ 的总答案,考虑每次 $mex$ 在变化的时候,原来 $mex$ 的贡献就是 $(l-last) imes mex$ ,将式子拆开,就是 $l imes mex-last imes mex$ ,于是可以用线段树维护 $mex$ 的和和以前历史的总和减去现在 $mex imes last$ 的值,查询时带 $l$ 下去查询即可。
效率: $O(nlogn)$
代码
#include <bits/stdc++.h> #define LL long long #define _(d) while(d(isdigit(c=getchar()))) using namespace std; int Rd(){ char c;_(!);int x=c^48; _()x=(x<<3)+(x<<1)+(c^48);return x; } const int N=1e6+5,M=N<<2; int Ty,n,nx[N],lst[N],a[N],q,b[N],ax[M],g[M][2]; LL ans[N],s[M][2],tg[M][2]; bool vis[N]; struct O{ int l,r,i,x; }p[N*2]; bool cmp(O A,O B){return A.x<B.x;} #define Ls k<<1 #define Rs k<<1|1 #define mid ((l+r)>>1) void down(int k,int l,int r){ if (!tg[k][0] && !tg[k][1]) return; s[k][0]+=tg[k][0]*(r-l+1); s[k][1]+=tg[k][1]*(r-l+1); if (l<r){ tg[Ls][0]+=tg[k][0];tg[Ls][1]+=tg[k][1]; tg[Rs][0]+=tg[k][0];tg[Rs][1]+=tg[k][1]; } tg[k][0]=tg[k][1]=0; } void up(int k,int l,int r){ s[k][0]=s[Ls][0]+(mid-l+1)*tg[Ls][0]+s[Rs][0]+(r-mid)*tg[Rs][0]; s[k][1]=s[Ls][1]+(mid-l+1)*tg[Ls][1]+s[Rs][1]+(r-mid)*tg[Rs][1]; g[k][0]=max(g[Ls][0],g[Rs][0]); g[k][1]=(g[Ls][1] || g[Rs][1] || g[Ls][0]!=g[Rs][0]); } void build(int k,int l,int r){ if (l==r){g[k][0]=s[k][0]=b[l];return;} build(Ls,l,mid);build(Rs,mid+1,r);up(k,l,r); } LL qry(int k,int l,int r,int L,int R,int i){ down(k,l,r); if (L<=l && r<=R) return s[k][0]*i+s[k][1]; if (mid>=R) return qry(Ls,l,mid,L,R,i); if (mid<L) return qry(Rs,mid+1,r,L,R,i); return qry(Ls,l,mid,L,R,i)+qry(Rs,mid+1,r,L,R,i); } void upd(int k,int l,int r,int L,int R,int i,int v){ if (l<r && !g[k][1]) g[Ls][0]=g[Rs][0]=g[k][0]; down(k,l,r); if (L<=l && r<=R && !g[k][1]){ tg[k][0]+=v-g[k][0]; tg[k][1]-=1ll*(v-g[k][0])*(i-1); g[k][0]=v; down(k,l,r); return; } if (mid>=L && g[Ls][0]>v) upd(Ls,l,mid,L,R,i,v); if (mid<R && g[Rs][0]>v) upd(Rs,mid+1,r,L,R,i,v); up(k,l,r); } int main(){ Ty=Rd();n=Rd(); for (int i=1;i<=n;i++){ a[i]=min(Rd(),n); nx[lst[a[i]]]=i,lst[a[i]]=i; } q=Rd(); for (int j=0,l,r,i=1;i<=q;i++){ l=Rd(),r=Rd(); p[++j]=(O){l,r,i,l-1}; p[++j]=(O){l,r,i,r}; } sort(p+1,p+q+q+1,cmp); for (int i=1;i<=n;i++){ vis[a[i]]=1;b[i]=b[i-1]; while(vis[b[i]]) b[i]++; if (!nx[i]) nx[i]=n+1; } build(1,1,n); int j=1; while(!p[j].x) j++; for (int i=1;i<=n;i++){ while(p[j].x==i) ans[p[j].i]+=(p[j].x<p[j].l?-1:1)* qry(1,1,n,p[j].l,p[j].r,i),j++; upd(1,1,n,i,nx[i]-1,i+1,a[i]); } for (int i=1;i<=q;i++) printf("%lld ",ans[i]); return 0; }
以上是关于漏网之鱼的主要内容,如果未能解决你的问题,请参考以下文章
面试官:你天天用 Lombok,说说它什么原理?我竟然答不上来…