HDU 5919 -- Sequence II (主席树)

题意:

给一串数字,每个数字的位置是这个数第一次出现的位置。

每个询问对于序列的一个子区间,设一共有k个不同的数,求第ceil(k/2)个数的位置。

因为强制在线,所以离线乱搞pass掉。

主席树可解。

考虑一个数列:

p      1 2 3 4 5 6  // 原序列标号

a : 1 2 1 2 3 4  // 原序列

p1  1 2 1 2 5 6  // 子序列开始下标为1

p2        2 3 1 5 6

p3           3 4 5 6

p4              4 5 6

p5                 5 6

p6                    6

有一个规律就是对于以L为开始的子序列来说,只要求出[L, N]的子区间,R是不影响P(L)数组的。

那么就想到将数组倒过来建主席树。

树里存的是什么呢????

存的是…【此处想了10分钟……】…区间内不同数的个数(只考虑第一次出现的)

那么在用一个数组记录每个数第一个出现的位置,每添加一个数,该位置+1,如果一个数之前出现过,那么就要更改之前第一次出现的位置-1。

不是很会主席树,之前就写过一道模板题= =  强行没看题解,一顿乱搞还是搞出来了,但是估计写的很麻烦

#include <bits/stdc++.h>
using namespace std;

const int N = 200005;

struct node {
    int l, r, v;
} T[N*40];

int a[N];
int pos[N];
int root[N], cnt;
int ans;
// y is x previous version
void update(int l, int r, int &x, int y, int p, int v) {
    T[++cnt] = T[y], T[cnt].v += v; x = cnt;
    if (l == r) return ;
    int mid = (l+r) >> 1;
    if (mid >= p) update(l, mid, T[x].l, T[y].l, p, v);
    else update(mid+1, r, T[x].r, T[y].r, p, v);
}

// p1 > p2
void update(int l, int r, int &x, int y, int p1, int v1, int p2, int v2) {
    T[++cnt] = T[y]; x = cnt;
    if (l == r) return ;
    int mid = (l+r) >> 1;
    // three conditions
    // p1 > mid >= p2,  p1 > p2 > mid,  mid >= p1 > p2
    if (p1 > mid && p2 <= mid) {
        update(mid+1, r, T[x].r, T[y].r, p1, v1);
        update(l, mid, T[x].l, T[y].l, p2, v2);
    } else if (p2 > mid) {
        update(mid+1, r, T[x].r, T[y].r, p1, v1, p2, v2);
    } else {
        update(l, mid, T[x].l, T[y].l, p1, v1, p2, v2);
    }
}

void query(int l, int r, int x, int k) {
    if (l == r) {
        ans = l; return ;
    }
    int mid = (l+r) >> 1;
    if (T[T[x].r].v >= k) {
        ans = mid+1;
        query(mid+1, r, T[x].r, k);
    } else {
        query(l, mid, T[x].l, k-T[T[x].r].v);
    }
}

int query(int l, int r, int x, int L, int R) {
    if (l >= L && r <= R) return T[x].v;
    int mid = (l+r) >> 1;
    int ans = 0;
    if (mid >= L) ans += query(l, mid, T[x].l, L, R);
    if (mid < R) ans += query(mid+1, r, T[x].r, L, R);
    return ans;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    int t, cas = 0;
    scanf("%d", &t);

    while (t--) {
        printf("Case #%d:", ++cas);
        ans = 0;
        int n, q, l_, r_, l, r, k;
        scanf("%d%d", &n, &q);
        memset(pos, 0, sizeof pos); cnt = 0;
        for (int i = 1; i <= n; ++i) scanf("%d", &a[n-i+1]);
        for (int i = 1; i <= n; ++i) {
            if (pos[a[i]]) update(1, n, root[i], root[i-1], i, 1, pos[a[i]], -1);
            else update(1, n, root[i], root[i-1], i, 1);
            pos[a[i]] = i;
        }
        while (q--) {
            scanf("%d%d", &l_, &r_);
            l_ = (l_ + ans) % n + 1;
            r_ = (r_ + ans) % n + 1;
            l = min(l_, r_);
            r = max(l_, r_);
            l = n-l+1, r = n-r+1; swap(l, r);
            k = query(1, n, root[r], l, r);
            query(1, n, root[r], ceil(k/2.0));
            ans = n-ans+1;
            printf(" %d", ans);
        }
        printf("\n");
    }
    return 0;
}
时间: 2024-08-01 22:45:27

HDU 5919 -- Sequence II (主席树)的相关文章

HDU 5919 Sequence II 主席树

Sequence II Problem Description Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,?,an There are m queries. In the i-th query, you are given two integers li and ri. Consider the subsequence ali,ali+1,ali+2,?,ari. We can deno

HDU 5919 Sequence II(主席树+逆序思想)

Sequence II Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 1422    Accepted Submission(s): 362 Problem Description Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2

HDU 5919 - Sequence II (2016CCPC长春) 主席树 (区间第K小+区间不同值个数)

HDU 5919 题意: 动态处理一个序列的区间问题,对于一个给定序列,每次输入区间的左端点和右端点,输出这个区间中:每个数字第一次出现的位子留下, 输出这些位子中最中间的那个,就是(len+1)/2那个. 思路: 主席树操作,这里的思路是从n到1开始建树.其他就是主席树查询区间第K小,计算区间不同值个数. #include <algorithm> #include <iterator> #include <iostream> #include <cstring&

HDU 5919 Sequence II(主席树)题解

题意:有A1 ~ An组成的数组,给你l r,L = min((l + ans[i - 1]) % n + 1, (r + ans[i - 1]) % n + 1),R = max((l + ans[i - 1]) % n + 1, (r + ans[i - 1]) % n + 1),你先需要的到L,R区间有k个不同的数字,然后问你L,R区间第(k + 1)/ 2个不同的数字下标是多少? 思路:显然是个在线询问. 我们之前已经会用主席树求区间内有多少不同数字了:从左到右把每个数字的位置存进每个操

HDU 5919 Sequence II

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5919 ------------------------------------------------------------------------------------ 现场赛的时候由于不会主席树就用分块卡过去了 现在学习了主席树后感觉这题也是很有意思的 首先 这题要把问题转化为对于一段区间 求一个左端点相同的$($如果有多个取右端点最靠左的$)$子区间 这个子区间的不同数的个数等于原区间不同

[ACM] hdu 5147 Sequence II (树状数组,前缀和,后缀和)

Sequence II Problem Description Long long ago, there is a sequence A with length n. All numbers in this sequence is no smaller than 1 and no bigger than n, and all numbers are different in this sequence. Please calculate how many quad (a,b,c,d) satis

Hdu 5147 Sequence II(树状数字 or 线段树 + 输入外挂 前缀和+后缀和)

题意: 给定1~n的一个排列 用A[]数组保存,问有多少下标(a,b,c,d)四元组满足: a 解析: 题目中n的范围是50000,O(n^2) 复杂度肯定超时.那么这题明显考察的是log2(n)的算法,对于这题可以用线段树或者树状数组,同时要用到输入外挂,不然会超时. 思路(参考别人做法) 枚举c的位置,那么每一次枚举中的方法数为 1~c-1 中(a,b)的个数 乘以 c~n中(c,d)的个数.累加起来即为答案. 1~c-1中(a,b)的个数相当于枚举b的位置,然后计算出b前面有多少数比A[b

hdu 5147 Sequence II(树状数组)

题目链接:hdu 5147 Sequence II 预处理每个位置作为b和c可以组成的对数,然后枚举b的位置计算. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 50005; int N, arr[maxn], fenw[maxn], lef[maxn], rig[maxn]; #d

HDU 3397 Sequence operation 线段树

线段树大杂烩~ 各种操作都有,细心点不难1A #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; #define lson rt<<1,l,mid #define rson rt<<1|1,mid + 1,r const int maxn = 1e5 + 10; int lmax[maxn