zoukankan      html  css  js  c++  java
  • [CF765F] Souvenirs

    Portal

    其实这题很套路。像 HNOI2017影魔 的模型,大概可以概括为:

    给定你一个序列,在不修改的前提下,求一个区间满足某种条件的二元组的个数/最值/和,条件一般和最值有关, 这就方便我们进行维护。

    解决此类问题的一般思路是,首先离线,然后在固定某个端点的情况下处理另一个端点。处理容易发现,另一个端点的值往往是满足某些类单调的性质。这就可以严格限制另一个端点扫到的元素个数,从而保证复杂度。 这里一般开一个线段树进行维护。

    在本题中,有端点必须满足$$ j' - j < j - i $$, 从而推出j递减的个数为(O(logn))次,可以采用主席树进行维护,进而用线段树维护历史二元组的值。

    复杂度似乎是 (O(nsqrt n)) 的莫队,链接

    详细题解:

    转载自:这里

    将所有询问离线,按右端点排序。

    枚举右端点r,用线段树维护对于当前的右端点,每个左端点对应的答案。

    线段树每个结点维护对应区间归并排序后的状态,即构造一棵归并树。

    插入新的右端点就相当于在线段树对应区间找到最接近的数,然后更新答案。

    显然暴力更新的复杂度在最坏情况下是单次(O(n))的。

    发现由于右端点固定,若左边的答案已经不会比右边优,则左端点已经没有更新的必要。先更新右子区间,再更新左子区间剪枝即可。

    时间复杂度(O(mlog^2n))

    Code:

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
    #define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
    #define clar(a, b) memset((a), (b), sizeof(a))
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    typedef long long LL;
    typedef long double LD;
    int read() {
        char ch = getchar();
        int x = 0, flag = 1;
        for (;!isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
        for (;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
        return x * flag;
    }
    void write(int x) {
        if (x < 0) putchar('-'), x = -x;
        if (x >= 10) write(x / 10);
        putchar(x % 10 + 48);
    }
    
    const int Maxn = 2e5 + 9, Maxm = 4e5 + 9, INF = 0x3f3f3f3f;
    int n, m, a[Maxn];
    vector <pair<int, int> > ls[Maxn];
    int ans[Maxm];
    
    struct BIT {
    	int c[Maxn];
    #define lowbit(x) ((x) & -(x))
    	void modify(int pos, int val) {
    		for (; pos; pos -= lowbit(pos)) c[pos] = min(c[pos], val);
    	}
    	int query(int pos) {
    		int res = 0x3f3f3f3f;
    		for (; pos < Maxn; pos += lowbit(pos)) res = min(res, c[pos]);
    		return res;
    	}
    #undef lowbit
    }s;
    
    int rt[Maxn];
    
    struct PresidentTree {
    	int ls[Maxn * 32], rs[Maxn * 32], Max[Maxn * 32], cnt;
    	void init() {
    		clar(ls, 0); clar(rs, 0); clar(Max, 0); cnt = 0;
    	}
    	int modify(int pre, int l, int r, int pos, int val) {
    		int o = ++cnt;
    		ls[o] = ls[pre]; rs[o] = rs[pre]; Max[o] = max(Max[o], val);
    		if (l == r) return o;
    		int mid = (l + r) >> 1;
    		(pos <= mid) ? ls[o] = modify(ls[pre], l, mid, pos, val) : rs[o] = modify(rs[pre], mid + 1, r, pos, val);
    		return o;
    	}
    
    	int query(int rt, int l, int r, int p, int q) {
    		if (p > q || !rt) return 0;
    		if (p <= l && r <= q) return Max[rt];
    		int mid = (l + r) >> 1;
    		if (q <= mid) return query(ls[rt], l, mid, p, q);
    		else if (p >= mid + 1) return query(rs[rt], mid + 1, r, p, q);
    		else return max(query(rs[rt], mid + 1, r, p, q), query(ls[rt], l, mid, p, q));
    	}
    }t;
    
    void init() {
    	clar(ans, 0x3f);
    
    	n = read(); 
    	rep (i, 1, n) a[i] = read();
    	m = read();
    	rep (i, 1, m) {
    		int l = read(), r = read();
    		ls[r].push_back(make_pair(l, i));
    	}
    }
    
    void calc() {
    	t.init(); clar(s.c, 0x3f);
    	rep (i, 1, n) rt[i] = t.modify(rt[i - 1], 1, 0x3f3f3f3f, a[i], i);
    
    	rep (i, 1, n) {
    		int cur = t.query(rt[i - 1], 1, 0x3f3f3f3f, a[i], 0x3f3f3f3f);
    
    		while (cur != 0) {
    			s.modify(cur, a[cur] - a[i]);
    			cur = t.query(rt[cur - 1], 1, 0x3f3f3f3f, a[i], (a[i] + a[cur]) / 2 - !((a[i] + a[cur]) & 1));
    		}
    
    		rep (j, 0, ls[i].size() - 1) ans[ls[i][j].second] = min(ans[ls[i][j].second], s.query(ls[i][j].first)); 
    	}
    }
    
    void solve() {
    	calc();
    
    	rep (i, 1, n) a[i] = 0x3f3f3f3f - a[i];
    	calc();
    	
    	rep (i, 1, m) printf("%d
    ", ans[i]);
    }
    
    int main() {
    	freopen("bridge.in", "r", stdin);
    	freopen("bridge.out", "w", stdout);
    
    	init();
    	solve();
    
    #ifdef Qrsikno
        debug("
    Running time: %.3lf(s)
    ", clock() * 1.0 / CLOCKS_PER_SEC);
    #endif
        return 0;
    }
    
  • 相关阅读:
    常见限流算法
    spring aop 事物
    Java序列化和反序列化为什么要实现Serializable接口
    java类在何时被加载?
    mysql 排序 是怎么工作的?
    程序员转正述职报告
    .NET中使用Channel<T>
    .NET-服务承载系统(Hosting)(支持Cron表达式)
    JObject拼接Json字符串
    NET5 使用FTP发布
  • 原文地址:https://www.cnblogs.com/qrsikno/p/10128898.html
Copyright © 2011-2022 走看看