#RMQ,ST表#hdu 6356 Glad You Came

题目

经过一波玄学的操作得到左端点 l ,右端点 r A [ l , r ] = max ( [ l , r ] , v a l u e )
多组数据,求 x o r i = 1 n A [ i ] i


分析

这道题首先先放玄学操作

int answer(){
    x^=(x<<11); x^=(x>>4); x^=(x<<5); x^=(x>>14);
    uit w=x^y^z; x=y; y=z; z=w; return z;
}
f1=answer(); f2=answer(); v=answer()%1073741824;
l=min(f1%n+1,f2%n+1); r=max(f1%n+1,f2%n+1);

不多说玄学操作QAQ
然后其它呢,怎样把答案从每个区间缩到单点,线段树?理论上查询 O ( l o g n ) 会超时,然并卵,所以就用一种神奇的逆ST表
f [ i ] [ j 1 ] = m a x { f [ i ] [ j 1 ] , f [ i ] [ j ] }
f [ i + 2 j 1 ] [ j 1 ] = m a x { f [ i + 2 j 1 ] [ j 1 ] , f [ i ] [ j ] }


代码

#include <cstdio>
#include <algorithm>
typedef unsigned uit;
uit f[100001][17],ln[100001],t,n,m,x,y,z;
uit in(){
    uit ans=0; char c=getchar();
    while (c<48||c>57) c=getchar();
    while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
    return ans;
}
void print(long long ans){if (ans>9) print(ans/10); putchar(ans%10+48);}
uit answer(){
    x^=(x<<11); x^=(x>>4); x^=(x<<5); x^=(x>>14);
    uit w=x^y^z; x=y; y=z; z=w; return z;
}
int main(){
    t=in();
    for (register uit i=2;i<=100000;i++) ln[i]=ln[i>>1]+1;
    while (t--){
        uit n,m,l,r,f1,f2,v,k; long long ans=0ll;
        n=in(); m=in(); x=in(); y=in(); z=in();
        while (m--){
            f1=answer(); f2=answer(); v=answer()%1073741824;
            l=std::min(f1%n+1,f2%n+1); r=std::max(f1%n+1,f2%n+1);
            k=ln[r-l+1]; f[l][k]=std::max(f[l][k],v); 
            f[r-(1<<k)+1][k]=std::max(f[r-(1<<k)+1][k],v);//首先得到两个区间增加
        }
        for (register uit j=ln[n];j>=1;j--)//RMQ
        for (register uit i=1;i<=n;i++){
            f[i][j-1]=std::max(f[i][j-1],f[i][j]);
            if (i+(1<<j-1)<=n) f[i+(1<<j-1)][j-1]=std::max(f[i+(1<<j-1)][j-1],f[i][j]);
            f[i][j]=0;
        }
        for (register long long i=1;i<=n;i++) ans^=f[i][0]*i,f[i][0]=0;//求答案
        if (ans) print(ans); else putchar('0'); putchar('\n');
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sugar_free_mint/article/details/81749607
今日推荐