【Codechef】【主席树维护DP】【SnackDown 2017 Online Elimination Round】PREFIXOR: 异或前缀

如果能处理出每个点往右最多扩展到 rgt[i] r g t [ i ] ,那么答案就是

i=lrmin{rgt[i],r}i=i=lrrgt[i]i=lrii=l&rgt[i]>rrrgt[i]r ∑ i = l r m i n { r g t [ i ] , r } − i = ∑ i = l r r g t [ i ] − ∑ i = l r i − ∑ i = l & r g t [ i ] > r r r g t [ i ] − r

只要用主席树维护就可以了(记 rgt[i] ∑ r g t [ i ] , i ∑ i ,个数)就可以统计了。

剩下的问题就是如何求 rgt[i] r g t [ i ] ,可以发现,如果 sum[i] s u m [ i ] sum[i1] s u m [ i − 1 ] 二进制下的最高不相等位会对前面的有一个限制,即只有当之前的 sum[j] s u m [ j ] 在这一位上是确定的值时才可以继续往后推,这样只要从后往前推一边就可以得到 rgt[i] r g t [ i ]

代码

#include
#include
#include
using namespace std;
typedef long long LL;
const int maxn=400006,maxm=10000000;
inline char nc(){static char buf[100000],*i=buf,*j=buf;return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;}
inline int _read(){char ch=nc();int sum=0;while(!(ch>='0'&&ch<='9'))ch=nc();while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();return sum;}
int n,t,T,len,rot[maxn],f[29][2],sum[maxn],rgt[maxn],ch[maxm][2];
struct data{
    int l,r,cnt;
    LL x,s;
}tree[maxm];
int newnode(int l,int r){len++;tree[len].l=l;tree[len].r=r;return len;}
int build(int l,int r){
    int x=newnode(l,r);
    if(l>=r)return x;
    int mid=l+r>>1;
    ch[x][0]=build(l,mid);ch[x][1]=build(mid+1,r);
    return x;
}
int update(int lst,int k,int sum){
    int x=++len;tree[x]=tree[lst];ch[x][0]=ch[lst][0];ch[x][1]=ch[lst][1];
    if(tree[lst].l==tree[lst].r)return tree[x].cnt++,tree[x].s+=sum,tree[x].x+=k,x;
    int mid=tree[x].l+tree[x].r>>1;
    if(k<=mid)ch[x][0]=update(ch[lst][0],k,sum);
         else ch[x][1]=update(ch[lst][1],k,sum);
    tree[x].s=tree[ch[x][0]].s+tree[ch[x][1]].s;tree[x].cnt=tree[ch[x][0]].cnt+tree[ch[x][1]].cnt;tree[x].x=tree[ch[x][0]].x+tree[ch[x][1]].x;
    return x;
}
LL query_s(int L,int R,int l,int r){
    if(tree[L].l>r||tree[L].rreturn 0;
    if(l<=tree[L].l&&r>=tree[L].r)return tree[R].s-tree[L].s;
    return query_s(ch[L][0],ch[R][0],l,r)+query_s(ch[L][1],ch[R][1],l,r);
}
LL query_cnt(int L,int R,int l,int r){
    if(tree[L].l>r||tree[L].rreturn 0;
    if(l<=tree[L].l&&r>=tree[L].r)return tree[R].cnt-tree[L].cnt;
    return query_cnt(ch[L][0],ch[R][0],l,r)+query_cnt(ch[L][1],ch[R][1],l,r);
}
LL query_x(int L,int R,int l,int r){
    if(tree[L].l>r||tree[L].rreturn 0;
    if(l<=tree[L].l&&r>=tree[L].r)return tree[R].x-tree[L].x;
    return query_x(ch[L][0],ch[R][0],l,r)+query_x(ch[L][1],ch[R][1],l,r);
}
int main(){
    freopen("xor.in","r",stdin);freopen("xor.out","w",stdout);
    n=_read();t=1;//t=_read();
    for(int i=1;i<=n;i++)sum[i]=sum[i-1]^_read();
    for(int i=0;i<=29;i++)f[i][0]=f[i][1]=n+1;
    for(int i=n;i>=1;i--){
        rgt[i]=n;for(int j=29;j>=0;j--)rgt[i]=min(rgt[i],f[j][(sum[i-1]>>j)&1]-1);
        for(int j=29;j>=0;j--) if(((sum[i]>>j)&1)!=((sum[i-1]>>j)&1)){f[j][(sum[i]>>j)&1]=i;break;}
    }
    rot[0]=build(1,n);
    for(int i=1;i<=n;i++)rot[i]=update(rot[i-1],rgt[i],rgt[i]-i+1);
    T=_read();int x,y,l,r;LL ans=0;
    while(T--){
        x=(_read()+ans*t)%n+1;y=(_read()+ans*t)%n+1;l=min(x,y);r=max(x,y);
        ans=query_s(rot[l-1],rot[r],l,n)+r*query_cnt(rot[l-1],rot[r],r+1,n)-query_x(rot[l-1],rot[r],r+1,n);
        printf("%lld\n",ans);
    }
    return 0;
}

你可能感兴趣的:(codechef,主席树)