2018 Multi-University Training Contest 5 G Glad You Came(hdu 6356)(ST)

题目链接:hdu 6356 Glad You Came

Sample Input
4
1 10 100 1000 10000
10 100 1000 10000 100000
100 1000 10000 100000 1000000
1000 10000 100000 1000000 10000000
 

Sample Output
1031463378
1446334207
351511856
47320301347

题意:函数生成f数列,a数列初始化为0,通过公式得到(l,r,v),表示将数列a的l到r区间值更新为max(a[i],v),最后输出所有a[i]*i的异或值

思路:线段树T了,应该是可以用但是我写的不够优秀吧,区间问题,所有更新结束以后输出一次值,ST比较合适,第一次用ST,但是要注意,这题是倒着的ST,是已知一个大的区间,更新小区间的最大值,可以看下面的题解。 

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 100005
using namespace std;
typedef unsigned long long ll;

ll stmax[maxn][20];//stmax[i][j]表示i到i+2^j-1区间的最大值 
int LOG[maxn];
int n,m;

const unsigned long long mod=1<<30;
unsigned x,y,z,w;
unsigned tang(){
	x^=(x<<11);
	x^=(x>>4);
	x^=(x<<5);
	x^=(x>>14);
	w=x^(y^z);
	x=y;
	y=z;
	z=w;
	return z;
}
void InitSt(){
    for(int j=19;j;j--){
        for(int i=1;i+(1<<j)-1<=n;i++){
        	stmax[i][j-1]=max(stmax[i][j-1],stmax[i][j]);
            stmax[i+(1<<(j-1))][j-1]=max(stmax[i+(1<<(j-1))][j-1],stmax[i][j]);
        }
    }
}
int main(){
	int t;
	scanf("%d",&t);
	LOG[2]=1;
	for(int i=3;i<maxn;i++){
		LOG[i]=LOG[i>>1]+1;
	}//这里如果不预处理,而是直接求会超时 
	while(t--){
		cin>>n>>m>>x>>y>>z;
		memset(stmax,0,sizeof(stmax));
		for(int i=1;i<=m;i++){
			int l=tang()%n+1;
			int r=tang()%n+1;
			ll w=tang()%mod;
			if(l>r)swap(l,r);
			//int d=(int)((double)log(r-l+1.0)/log(2.0)); 这样求超时
			int d=LOG[r-l+1];
			stmax[l][d]=max(stmax[l][d],w);
			stmax[r-(1<<d)+1][d]=max(stmax[r-(1<<d)+1][d],w);
		}
		InitSt();
		ll ans=0;
		for(ll i=1;i<=n;i++){
			ans^=(stmax[i][0]*i);
		}
		cout<<ans<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/yz467796454/article/details/81461434
今日推荐