HDU 6356(ST表)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kzn2683331518/article/details/81568497

题意描述:

给出数据生成规则生成m组L,R,V,表示区间【L,R】中小于V的都更新为V。

求最后对全部的a[i]*i 取异或和的结果

题目分析:

ST表:

st[i][j]表示从i开始的2^j个数的最大值     //ST[N][logN]

第二维的大小是logN,可以理解为ST表的层数,第 j 层的每个位置维护从该位置开始2^j 个数的信息

那么每次更新【L,R】,找到最大的2^k的k小于等于R-L+1

只需要更新st[L][k]和st[R-(1<<k)+1][k]就能完整地把区间【L,R】给覆盖住,这样的更新操作需要的时间只有O(1)

在m次操作进行完成之后,这个st表上零零散散的有很多区间最大值,叠在各个层

我们从最高层(也就是维护着最后续区间的层)开始向下递推更新最大值,直至最底层,复杂度O(NlogN)

递推完成之后的每个st[i][0]就是操作后每个位置的数值了,查询O(1)

AC代码:

#include<iostream>
#include<stdio.h>
#define ll long long
using namespace std;
unsigned x,y,z,w,n,m;
int st[200005][18]; //st[i][j]表示从i开始的2^j个数的最大值
int lg[200005];
inline unsigned rng61(){
    x^=(x<<11); x^=(x>>4);  x^=(x<<5);  x^=(x>>14);
    w=(x^y^z);  x=y;        y=z;        z=w;
    return z;
}
inline void init(){//log2打表
    lg[0] = -1;
    for(int i = 1;i< 100005;i++)
        lg[i] = lg[i-1] + ((i&(i-1)) == 0);
}
inline void getop(int &l,int &r,int &v){
    unsigned f1=rng61(),f2=rng61();
    l=min(f1%n+1,f2%n+1), r=max(f1%n+1,f2%n+1);
    v=rng61()%1073741824;
}
int main(){
    int t,l,r,v,k;
    init();
    scanf("%d",&t);
    while(t--){
        scanf("%d %d %d %d %d",&n,&m,&x,&y,&z);
        for(int i=0;i<m;i++){
            getop(l,r,v);
            k=lg[r-l+1];
            //区间[l,r]的值对v取最大值更新
            st[l][k]=max(st[l][k],v);
            st[r-(1<<k)+1][k]=max(st[r-(1<<k)+1][k],v);
        }
        for(int i=lg[n];i>=1;i--){//从区间长度最大向下递推,类似线段树pushdown
            for(int j=1;j<=n;j++){
                st[j][i-1]=max(st[j][i-1],st[j][i]);
                st[j+(1<<(i-1))][i-1] = max(st[j+(1<<(i-1))][i-1],st[j][i]);
                st[j][i]=0;
            }
        }
        ll ans=0;
        for(ll i = 1;i<= n;i++){
            ans^= (st[i][0]*i);
            st[i][0] = 0;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/kzn2683331518/article/details/81568497
今日推荐