题目:http://acm.hdu.edu.cn/showproblem.php?pid=6356
用线段树维护一个最小最大值搞一下可以过:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#define ls (o*2)
#define rs ((o*2)+1)
#define mid ((l+r)/2)
using namespace std;
typedef unsigned uns;
typedef long long int ll;
const int maxn = 100000;
const int maxm = 5000000;
int n,m,pos[maxn+5];
uns mx[maxn*4+5],mi[maxn*4+5], f[maxm*3+5],st[maxn*4+5];
uns X,Y,Z,W;
unsigned F()
{
X=X^(X<<11);
X=X^(X>>4);
X=X^(X<<5);
X=X^(X>>14);
W=X^(Y^Z);
X=Y;
Y=Z;
Z=W;
return Z;
}
void pushup(int o)
{
mx[o] = max(mx[ls],mx[rs]);
mi[o] = min(mi[ls],mi[rs]);
}
void pushdown(int o)
{
if(st[o]!=-1)
{
st[ls] = st[rs] = st[o];
mx[ls] = mx[rs] = st[o];
mi[ls] = mi[rs] = st[o];
st[o] = -1;
}
}
void build(int o,int l,int r)
{
st[o] = -1;
mx[o] = mi[o] = 0;
if(l==r)
{
pos[l] = o, mx[o] = 0, mi[o] = 0;
return;
}
build(ls,l,mid);
build(rs,mid+1,r);
}
void updata(int o,int l,int r,int L,int R,uns w)
{
if(r<L||R<l) return;
if(mi[o]>=w) return;//最小都大于等于w不用更新
if(L<=l&&r<=R)
{
if(mx[o]<=w)//最大都小于w就直接更新
{
st[o] = w,mx[o] = mi[o] = w;
}
else
{
pushdown(o);
if(mi[ls]<w) updata(ls,l,mid,L,R,w);
if(mi[rs]<w) updata(rs,mid+1,r,L,R,w);
pushup(o);
}
return;
}
pushdown(o);
if(L<=mid) updata(ls,l,mid,L,R,w);
if(mid<R) updata(rs,mid+1,r,L,R,w);
pushup(o);
}
void UP(int o,int l,int r)//把标记传下去
{
if(l==r) return;
pushdown(o);
UP(ls,l,mid);
UP(rs,mid+1,r);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d %d %u %u %u",&n,&m,&X,&Y,&Z);
build(1,1,n);
for(int i=1; i<=m*3; i++) f[i] = F();
for(int i=1; i<=m; i++)
{
uns L,R,v;
L = min(f[3*i-2]%n+1,f[3*i-1]%n+1);
R = max((f[3*i-2] % n) + 1,(f[3*i-1] % n) + 1);
v = f[3*i]%(1ll<<30);
updata(1,1,n,L,R,v);
}
UP(1,1,n);
ll ans = 0;
for(int i=1; i<=n; i++) ans^=mx[pos[i]]*1ll*i;
printf("%lld\n",ans);
}
return 0;
}
题解的解法:
学到了,真的不错。
/*
ST表反过来用。
d[i][j] 表示 j开始 2^i 个数的最大值,
用 d[i][j] 去更新 d[i-1][j] ,d[i-1][j-2^(i-1)+1].
最后从高到低把值更新
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = (int)1e5 + 1, maxd = 17;
int t, n, m, mx, Log[maxn], a[maxd][maxn];
unsigned int X, Y, Z;
unsigned int rng61() {
X ^= X << 11;
X ^= X >> 4;
X ^= X << 5;
X ^= X >> 14;
unsigned int tmp = X ^ Y ^ Z;
X = Y;
Y = Z;
Z = tmp;
return Z;
}
inline void upd(int &x, int y) {
x < y && (x = y);
}
int main() {
for(int i = 2; i < maxn; ++i)
Log[i] = Log[i >> 1] + 1;
scanf("%d", &t);
while(t--) {
scanf("%d%d%u%u%u", &n, &m, &X, &Y, &Z);
for(mx = 0; 1 << mx <= n; ++mx);
while(m--) {
int L = rng61() % n + 1, R = rng61() % n + 1, v = rng61() & ((1 << 30) - 1);
if(L > R)
swap(L, R);
int d = Log[R - L + 1];
upd(a[d][L], v);
upd(a[d][R - (1 << d) + 1], v);
}
for(int i = mx - 1; i > 0; --i)
for(int j = 1; j + (1 << i) - 1 <= n; ++j) {
upd(a[i - 1][j], a[i][j]);
upd(a[i - 1][j + (1 << (i - 1))], a[i][j]);
a[i][j] = 0;
}
LL ans = 0;
for(int i = 1; i <= n; ++i) {
ans ^= (LL)i * a[0][i];
a[0][i] = 0;
}
printf("%lld\n", ans);
}
return 0;
}