[二分 ST表 杂题] Codeforces875D. High Cry

来源:互联网 发布:windows信息发布系统 编辑:程序博客网 时间:2024/06/06 10:58

早知道先看D题就不会掉这么惨了

枚举左端点,那么区间或值最多变化log次

二分变化的区间,再二分区间或值大于区间最大值的区间

用ST表记一下区间最大值、或值

#include <cstdio> #include <algorithm>#include <iostream>using namespace std;typedef long long ll;const int N=200010;int n,a[N],lg2[N];int ior[N][20],imax[N][20];inline void Pre(){    for(int i=1;i<=n;i++) lg2[i]=lg2[i-1]+((1<<lg2[i-1]+1)==i);    int t=lg2[n];    for(int i=1;i<=n;i++) ior[i][0]=imax[i][0]=a[i];    for(int k=1;k<=t;k++)        for(int i=1;i+(1<<k)-1<=n;i++)            ior[i][k]=ior[i][k-1]|ior[i+(1<<k-1)][k-1],imax[i][k]=max(imax[i][k-1],imax[i+(1<<k-1)][k-1]);}inline int Qor(int l,int r){    int t=lg2[r-l+1];    return ior[l][t]|ior[r+1-(1<<t)][t];}inline int Qmax(int l,int r){    int t=lg2[r-l+1];    return max(imax[l][t],imax[r-(1<<t)+1][t]);}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++) scanf("%d",&a[i]);    Pre(); ll ans=0;    for(int i=1;i<=n;i++){        int cur=a[i],j=i;        while(j<=n){            int l=j,r=n,mid,nxt;            while(l<=r) Qor(i,mid=l+r>>1)==cur?l=(nxt=mid)+1:r=mid-1;            l=j; r=nxt; int pos=-1;            while(l<=r) Qmax(i,mid=l+r>>1)<cur?l=(pos=mid)+1:r=mid-1;            if(~pos) ans+=pos-j+1;            j=nxt+1; cur=Qor(i,j);        }    }    cout<<ans<<endl;    return 0;}