QUERY [ 单调栈 ]
用单调栈预处理出第一个比$a[i]$大/小的数的位置。
然后枚举左端点$i$,不断拓展右端点$now$,维护$i$~$now$的最大值$ma$、最小值$mi$,$ans$加上$ma$&$mi$乘增加的区间。
1 #include<bits/stdc++.h> 2 #define LL long long 3 using namespace std; 4 const int N=1e5+5; 5 int n,a[N],Min[N],Max[N],top,s[N]; 6 LL ans; 7 inline int read() { 8 int x=0,f=1; char c=getchar(); 9 while(c<'0'||c>'9') {if(c=='-')f=-1; c=getchar();} 10 while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar(); 11 return x*f; 12 } 13 14 void prepare() { 15 for(int i=1;i<=n;i++) { 16 while(top&&a[i]<a[s[top]]) 17 Min[s[top]]=i,top--; 18 s[++top]=i; 19 20 } 21 while(top) Min[s[top]]=n+1,top--; 22 for(int i=1;i<=n;i++) { 23 while(top&&a[i]>a[s[top]]) 24 Max[s[top]]=i,top--; 25 s[++top]=i; 26 } 27 while(top) Max[s[top]]=n+1,top--; 28 } 29 30 int main() { 31 freopen("query.in","r",stdin); 32 freopen("query.out","w",stdout); 33 n=read(); 34 for(int i=1;i<=n;i++) a[i]=read(); 35 prepare(); 36 for(int i=1;i<=n;i++) { 37 int mi=i,ma=i,now=i; 38 while(now<=n) { 39 if(Max[ma]<Min[mi]) { 40 ans+=(LL)(a[mi]&a[ma])*(Max[ma]-now); 41 ma=Max[ma]; 42 } 43 else { 44 ans+=(LL)(a[mi]&a[ma])*(Min[mi]-now); 45 mi=Min[mi]; 46 } 47 now=max(ma,mi); 48 } 49 } 50 printf("%lld",ans); 51 return 0; 52 }
如有错误请指正。