zoukankan      html  css  js  c++  java
  • [BZOJ3489]A simple rmq problem

    [BZOJ3489]A simple rmq problem

    试题描述

    因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。

    输入

    第一行为两个整数N,MM是询问数,N是序列的长度(N<=100000M<=200000)

    第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N

    再下面M行,每行两个整数xy

    询问区间[l,r]由下列规则产生(OIER都知道是怎样的吧>_<)

    l=min(x+lastans)mod n+1,(y+lastansmod n+1);

    r=max(x+lastans)mod n+1,(y+lastansmod n+1);

    Lastans表示上一个询问的答案,一开始lastans0

    注意出题人为了方便,input的第二行最后多了个空格。

    输出

    一共M行,每行给出每个询问的答案。

    输入示例

    10 10
    6 4 9 10 9 10 9 4 10 4 
    3 8
    10 1
    3 4
    9 4
    8 1
    7 8
    2 9
    1 1
    7 3
    9 9

    输出示例

    4
    10
    10
    0
    0
    10
    0
    4
    0
    4

    数据规模及约定

    见“输入

    题解

    预处理一下,对于每一个数,将离它最近的与它相等的数的位置求出来,左边的位置表示成 pre[i],右边的位置表示成 nxt[i],如果没有左边的相同的数字则 pre[i] = 0,若没有右边的相同的数字则 nxt[i] = n + 1. 那么第 i 个数在空间中可以表示成 (i, pre[i], nxt[i]) 这个点,当一个询问 [L, R] 到来时,就是查询所有满足 L <= i <= R & pre[i] < L & R < nxt[i] 的最大点权。不难发现这是一个空间中的长方体,可以用树套树套树解决。

    当然只有区间查询的 kd 树还是有复杂度保证的。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <stack>
    #include <vector>
    #include <queue>
    #include <cstring>
    #include <string>
    #include <map>
    #include <set>
    #include <ctime>
    using namespace std;
    
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *Tail;
    inline char Getchar() {
    	if(Head == Tail) {
    		int l = fread(buffer, 1, BufferSize, stdin);
    		Tail = (Head = buffer) + l;
    	}
    	return *Head++;
    }
    int read() {
    	int x = 0, f = 1; char c = Getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
    	return x * f;
    }
    
    #define maxn 100010
    #define oo 2147483647
    int n, m, root, lc[maxn], rc[maxn], Cur, A[maxn], now[maxn];
    struct Node {
    	int x[3], mx[3], mn[3], val, maxv;
    	bool operator < (const Node& t) const { return x[Cur] < t.x[Cur]; }
    } ns[maxn];
    
    void maintain(int o) {
    	int l = lc[o], r = rc[o];
    	for(int i = 0; i < 3; i++) {
    		ns[o].mx[i] = max(max(ns[l].mx[i], ns[r].mx[i]), ns[o].x[i]);
    		ns[o].mn[i] = min(min(ns[l].mn[i], ns[r].mn[i]), ns[o].x[i]);
    	}
    	ns[o].maxv = max(max(ns[l].maxv, ns[r].maxv), ns[o].val);
    	return ;
    }
    void build(int& o, int L, int R, int cur) {
    	if(L > R){ o = 0; return ; }
    	int M = L + R >> 1; o = M;
    	Cur = cur; nth_element(ns + L, ns + M, ns + R + 1);
    	build(lc[o], L, M - 1, (cur + 1) % 3); build(rc[o], M + 1, R, (cur + 1) % 3);
    	maintain(o);
    	return ;
    }
    int ql, qr;
    bool all(int o) { return ql <= ns[o].mn[0] && ns[o].mx[0] <= qr && ns[o].mx[1] < ql && ns[o].mn[2] > qr; }
    bool has(int o) { return ql <= ns[o].mx[0] && ns[o].mn[0] <= qr && ns[o].mn[1] < ql && ns[o].mx[2] > qr; }
    int query(int o) {
    	if(!o) return 0;
    	int ans = 0, l = lc[o], r = rc[o];
    	if(ns[l].maxv > ns[r].maxv) {
    		if(ns[l].maxv > ans) {
    			if(all(l)) ans = max(ans, ns[l].maxv);
    			else if(has(l)) ans = max(ans, query(l));
    		}
    		if(ns[r].maxv > ans) {
    			if(all(r)) ans = max(ans, ns[r].maxv);
    			else if(has(r)) ans = max(ans, query(r));
    		}
    	}
    	else {
    		if(ns[r].maxv > ans) {
    			if(all(r)) ans = max(ans, ns[r].maxv);
    			else if(has(r)) ans = max(ans, query(r));
    		}
    		if(ns[l].maxv > ans) {
    			if(all(l)) ans = max(ans, ns[l].maxv);
    			else if(has(l)) ans = max(ans, query(l));
    		}
    	}
    	int x = ns[o].x[0], pre = ns[o].x[1], nxt = ns[o].x[2];
    	if(ql <= x && x <= qr && pre < ql && nxt > qr) ans = max(ans, ns[o].val);
    	return ans;
    }
    
    int main() {
    //	freopen("data.in", "r", stdin);
    //	freopen("data.out", "w", stdout);
    //	int clo = clock();
    	ns[0].mx[0] = ns[0].mx[1] = ns[0].mx[2] = -oo;
    	ns[0].mn[0] = ns[0].mn[1] = ns[0].mn[2] = oo;
    	ns[0].maxv = -oo;
    	n = read(); m = read();
    	for(int i = 1; i <= n; i++) {
    		A[i] = read();
    		ns[i].x[0] = i; ns[i].x[1] = now[A[i]];
    		now[A[i]] = i;
    	}
    	for(int i = 1; i <= n; i++) now[i] = n+1;
    	for(int i = n; i; i--) {
    		ns[i].x[2] = now[A[i]]; ns[i].maxv = ns[i].val = A[i];
    		now[A[i]] = i;
    	}
    	
    	build(root, 1, n, 0);
    	int lastans = 0;
    	while(m--) {
    		int x = read(), y = read();
    		ql = min((x + lastans) % n + 1, (y + lastans) % n + 1);
    		qr = max((x + lastans) % n + 1, (y + lastans) % n + 1);
    		lastans = query(root);
    		printf("%d
    ", lastans);
    	}
    //	printf("%d
    ", clock() - clo);
    	
    	return 0;
    }
    
  • 相关阅读:
    MVC 传值
    LINQ to SQL 语句(2)之 Select/Distinct
    LINQ to SQL 语句(1)之 Where
    输入变量相同情况下,结果不正确
    vmware ubuntu 切换终端命令行
    汉字编码问题
    Windows API所提供的功能可以归为七类
    比较好的c++博文
    环境和库的引入
    C#调用Fortran生成的DLL的方法报内存不足
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5688879.html
Copyright © 2011-2022 走看看