Glad You Came hdu-6356(ST表 || 线段树)

第一种用线段树,用两颗数维护区间最大值和区间的最小值,然后更新的时候如果我目前区间内的最大值比我得到的v小,那么我就把这个区间修改成v,如果我的最小值比v大,那么v就是没有用的,直接跳过,然后这样每次更新[l, r]内的最大最小值,查询的时候返回每个位置的最大值,就可以求出答案

线段树:

#include<map>
#include<set>
#include<ctime>
#include<cmath>
#include<stack>
#include<queue>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lowbit(x) (x & (-x))

typedef unsigned long long int ull;
typedef long long int ll;
typedef unsigned int ui;
const double pi = 4.0*atan(1.0);
const int inf = 0x3f3f3f3f;
const int maxn = 1e5;
const int maxm = 2e5+10;
const int mod = 1<<30;
const double eps = 1e-8;
using namespace std;

int n, m;
int T, tol;
ui X, Y, Z;
int mx[maxn << 2];
int mn[maxn << 2];
int lazy[maxn << 2];

ui RNG61() {
    X = X ^ (X<<11);
    X = X ^ (X>>4);
    X = X ^ (X<<5);
    X = X ^ (X>>14);
    ll W = X ^ (Y ^ Z);
    X = Y;
    Y = Z;
    Z = W;
    return Z;
}

void init() {
    memset(mx, 0, sizeof mx);
    memset(mn, 0, sizeof mn);
    memset(lazy, 0, sizeof lazy);
}

void pushup(int root) {
    mx[root] = max(mx[root << 1], mx[root << 1 | 1]);
    mn[root] = min(mn[root << 1], mn[root << 1 | 1]);
}

void pushdown(int root) {
    if(lazy[root]) {
        mx[root << 1] = mx[root << 1 | 1] = lazy[root];
        mn[root << 1] = mn[root << 1 | 1] = lazy[root];
        lazy[root << 1] = lazy[root << 1 | 1] = lazy[root];
        lazy[root] = 0;
    }
}

void update(int left, int right, int prel, int prer, int val, int root) {
    if(prel <= left && right <= prer) {
        if(mx[root] < val) {
            mx[root] = mn[root] = val;
            lazy[root] = val;
            return ;
        }
        if(mn[root] > val)    return ;
    }
    if(mn[root] > val)    return ;
    pushdown(root);
    int mid = (left + right) >> 1;
    if(prel <= mid)    update(left, mid, prel, prer, val, root << 1);
    if(prer > mid)    update(mid+1, right, prel, prer, val, root << 1 | 1);
    pushup(root);
}

int query(int left, int right, int pos, int root) {
    if(left == right) {
        return mx[root];
    }
    pushdown(root);
    int mid = (left + right) >> 1;
    if(pos <= mid)    return query(left, mid, pos, root << 1);
    else            return query(mid+1, right, pos, root << 1 | 1);
}

int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d%d%d%d", &n, &m, &X, &Y, &Z);
        init();
        for(int i=1; i<=m; i++) {
            ui f1 = RNG61();
            ui f2 = RNG61();
            ui f3 = RNG61();
            int l = min(f1%n+1, f2%n+1);
            int r = max(f1%n+1, f2%n+1);
            int v = f3 % mod;
            update(1, n, l, r, v, 1);
        }
        ll ans = 0;
        for(int i=1; i<=n; i++) {
            ans ^= (1ll * i * query(1, n, i, 1));
        }
        printf("%I64d
", ans);
    }
    return 0;
}
View Code

原本的RMQ是得到每个位置的点值,然后一步一步更新成区间的最值,用

st[i][j] = max(st[i][j-1],st[i+(1<<(j-1))][j-1])

然后这里是先得到区间最值,然后往回更新到每个位置的点的最值,所以就是两个

st[i][j-1] = max(st[i][j-1], st[i][j])

st[i+(1<<(j-1))][j-1] = max(st[i+(1<<(j-1))][j-1], st[i][j])

倒着更新

然后题目里面数据很大,所以同样的log(r-l+1)/log(2.0)可能计算很多遍,可以把log(i)/log(2.0)打表出来,可以快一半的时间

ST表:

#include<map>
#include<set>
#include<ctime>
#include<cmath>
#include<stack>
#include<queue>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lowbit(x) (x & (-x))

typedef unsigned long long int ull;
typedef long long int ll;
typedef unsigned int ui;
const double pi = 4.0*atan(1.0);
const int inf = 0x3f3f3f3f;
const int maxn = 1e5;
const int maxm = 2e5+10;
const int mod = 1<<30;
const double eps = 1e-8;
using namespace std;

int n, m;
int T, tol;
ui X, Y, Z;

int st[maxm][20];
int lg[maxn];

ui RNG61() {
    X = X ^ (X<<11);
    X = X ^ (X>>4);
    X = X ^ (X<<5);
    X = X ^ (X>>14);
    ll W = X ^ (Y ^ Z);
    X = Y;
    Y = Z;
    Z = W;
    return Z;
}

void init() {
    memset(st, 0, sizeof st);
}

void handle() {
    lg[0] = -1;
    for(int i=1; i<maxn; i++)    lg[i] = log(i) / log(2.0);
}

int main() {
    handle();
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d%d%d%d", &n, &m, &X, &Y, &Z);
        init();
        for(int i=1; i<=m; i++) {
            ui f1 = RNG61();
            ui f2 = RNG61();
            ui f3 = RNG61();
            int l = min(f1%n+1, f2%n+1);
            int r = max(f1%n+1, f2%n+1);
            int v = f3 % mod;
            int k = lg[r-l+1];
            st[l][k] = max(st[l][k], v);
            st[r-(1<<k)+1][k] = max(st[r-(1<<k)+1][k], v);
        }
        int len = log(n) / log(2.0);
        for(int j=len; j>=1; j--) {
            for(int i=1; i<=n; i++) {
                st[i][j-1] = max(st[i][j-1], st[i][j]);
                st[i+(1<<(j-1))][j-1] = max(st[i+(1<<(j-1))][j-1], st[i][j]);
            }
        }
        ll ans = 0;
        for(int i=1; i<=n; i++)        ans = ans ^ (1ll * i * st[i][0]);
        printf("%I64d
", ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Jiaaaaaaaqi/p/9487655.html