NOI模拟(5.7) HNOID1T2 转盘 (bzoj5286)

转盘

题目背景:

5.7 模拟 HNOI2018D1T2  

分析:线段树

 

又是神题一道,考场上连暴力都不会打,完全下不了手。

首先有一个非常显然的结论,对于每个询问,一定有一种最优解是从某个点开始先等待一段时间,然后直接走完一圈,考虑一个大致的证明,如果我们在不是起始点的其他点停顿的话,在相同时间的情况下,会导致除了这个点和这个点之后的其他所有点的最后一个位置提前(显然只有最后一次出现的位置有用),所以肯定不优,那么我们就证明了这个结论。

为了方面后面的推导,我们考虑把序列倍长,那么我们需要求的就



这样就可以直接用线段树维护出答案,每一次直接取根的val即可。具体细节详见代码,时间复杂度O(nlog2n)

 

Source:


/*
    created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>
 
inline char read() {
    static const int IN_LEN = 1024 * 1024;
    static char buf[IN_LEN], *s, *t;
    if (s == t) {
        t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
        if (s == t) return -1;
    }
    return *s++;
}
 
///*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = read(), iosig = false; !isdigit(c); c = read()) {
        if (c == -1) return ;
        if (c == '-') iosig = true; 
    }
    for (x = 0; isdigit(c); c = read()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN];
char *oh = obuf;
inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}


template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
	fwrite(obuf, 1, oh - obuf, stdout), oh = obuf;
}
 
/*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
        if (c == '-') iosig = true; 
    for (x = 0; isdigit(c); c = getchar()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/

const int MAXN = 200000 + 10;

int n, x, y, m, p;
int a[MAXN];

struct node {
    int val, max;
} tree[MAXN << 2 | 1];

inline int query(int k, int l, int r, int val) {
    if (l == r) return std::max(tree[k].max, val) + l;
    int mid = l + r >> 1;
    if (val <= tree[k << 1 | 1].max) 
        return std::min(tree[k].val, query(k << 1 | 1, mid + 1, r, val));
    else return std::min(query(k << 1, l, mid, val), mid + 1 + val);
}

inline void update(int k, int l, int mid) {
    tree[k].val = query(k << 1, l, mid, tree[k << 1 | 1].max);
    tree[k].max = std::max(tree[k << 1].max, tree[k << 1 | 1].max);
}

inline void build(int k, int l, int r) {
    if (l == r) {
        int cur = (l > n) ? (a[l - n] - l) : (a[l] - l);
        tree[k].max = cur, tree[k].val = cur + l;
        return ;
    }
    int mid = l + r >> 1;
    build(k << 1, l, mid), build(k << 1 | 1, mid + 1, r);
    update(k, l, mid);
}

inline void modify(int k, int l, int r, int pos, int x) {
    if (l == r) {
        tree[k].max = x, tree[k].val = x + l;
        return ;
    }
    int mid = l + r >> 1;
    if (pos <= mid) modify(k << 1, l, mid, pos, x);
    else modify(k << 1 | 1, mid + 1, r, pos, x);
    update(k, l, mid);
}

inline void solve() {
    int last;
    R(n), R(m), R(p);
    for (int i = 1; i <= n; ++i) R(a[i]);
    build(1, 1, 2 * n), W((last = tree[1].val + n - 1)), write_char('\n');
    while (m--) {
        R(x), R(y);
        if (p) x ^= last, y ^= last;
        modify(1, 1, 2 * n, x, y - x), modify(1, 1, 2 * n, x + n, y - x - n);
        W((last = tree[1].val + n - 1)), write_char('\n');
    }
}

int main() {
    //freopen("in.in", "r", stdin);
    solve();
    flush();
    return 0;
}

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/scar_lyw/article/details/80256341
文章标签: NOI 线段树
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭