• 洛谷P4425 [HNOI/AHOI2018]转盘(线段树)


    题意

    题目链接

    Sol

    首先猜一个结论:对于每次询问,枚举一个起点然后不断等到某个点出现时才走到下一个点一定是最优的。

    证明不会,考场上拍了3w组没错应该就是对的吧。。。

    首先把数组倍长一下方便枚举起点,然后就是一个单调队列的模型了。整理一下我们需要求的东西就是这个

    [n - 1 + min_{i=1}^n i + (max_{j=i}^{2n} t[j] - j) ]

    ((t[j])表示第(j)个位置出现的时间,其实(max)的上界应该是(i + n - 1)的,但是显然后面的部分都不会更优)

    其中(n-1)(t[j] - j)可以直接算,这玩意儿可以用线段树维护。

    对于每个区间维护(mx[i])表示区间最大值,(ans[i])表示在右区间的影响下,左区间的(min(i + max ext{后缀}))

    合并时考虑右区间对左区间的影响。

    如果(mx[rs] < mx[ls]),我们可以直接用(ans[ls])更新答案,然后递归(ls(rs))

    否则用mid更新一下答案然后递归(ls(ls))

    这样每次可以消除掉一半的区间,因此复杂度是(O(nlog^2n))

    最后询问的时候可以直接拿([n + 1, 2n])的最大值去二分,实际上这部分的值就是(max[1, n] - n)

    那么只需要维护([1, n])的线段树就行了

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 2e6 + 10, INF = 1e9 + 7;
    template<typename A, typename B> inline bool chmin(A &x, B y) {
    	if(x > y) {x = y; return 1;}
    	else return 0;
    }
    template<typename A, typename B> inline bool chmax(A &x, B y) {
    	if(x < y) {x = y; return 1;}
    	return 0;
    }
    inline int read() {
    	char c = getchar(); int x = 0, f = 1;
    	while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return x * f;
    }
    int N, M, P, t[MAXN],  q[MAXN];
    int ans[MAXN], mx[MAXN];
    #define ls k << 1
    #define rs k << 1 | 1
    int Query(int k, int l, int r, int val) {
    	if(l == r) return l + max(mx[k], val);
    	int mid = l + r >> 1;
    	if(val < mx[rs]) return min(ans[k], Query(rs, mid + 1, r, val));
    	else return min(mid + val + 1, Query(ls, l, mid, val));	
    }
    void update(int k, int l, int r) {
    	mx[k] = max(mx[ls], mx[rs]);
    	ans[k] = Query(ls, l, (l + r) >> 1, mx[rs]);
    }
    void Modify(int k, int l, int r, int p, int v) {
    	if(l == r) {mx[k] = v; return ;}
    	int mid = l + r >> 1;
    	if(p <= mid) Modify(ls, l, mid, p, v);
    	else Modify(rs, mid + 1, r, p, v);
    	update(k, l, r);
    }
    void Build(int k, int l, int r) {
    	if(l == r) {mx[k] = t[l]; return ;}
    	int mid = l + r >> 1;
    	Build(ls, l, mid); Build(rs, mid + 1, r);
    	update(k, l, r);
    }
    int main() {
    	N = read(); M = read(); P = read();
    	for(int i = 1; i <= N; i++) t[i] = read();
    	for(int i = 1; i <= N; i++) t[i] -= i;
    	Build(1, 1, N); int las = 0;
    	printf("%d
    ", las = (Query(1, 1, N, mx[1] - N) + N - 1));
    	while(M--) {
    		int x = read(), y = read();
    		if(P) x ^= las, y ^= las;
    		Modify(1, 1, N, x, y - x);
    		printf("%d
    ", las = (Query(1, 1, N, mx[1] - N) + N - 1));
    	}
    	return 0;
    }
    /*
    5 0 0
    1 2 5 4 0
    */
    
  • 相关阅读:
    逻辑卷的创建
    文件及目录的权限详解
    python之数据驱动Excel+ddt操作(方法二)
    python之数据驱动Excel操作(方法一)
    python + Excel数据读取(更新)
    selenium3 + python
    python+selenium+unittest发送Mail163邮件(PO)
    python自动发邮件库yagmail
    python之数据驱动yaml操作
    python之数据驱动ddt操作(方法四)
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/10417387.html
Copyright © 2020-2023  润新知