2018 Multi-University Training Contest 5 Glad You Came

题目: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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值