2016CCPC长春:Sequence II(主席树)

来源:互联网 发布:手机excel求和软件 编辑:程序博客网 时间:2024/05/16 06:21

问题概述:n个数q次查询,每次查询(l,r)表示查询区间[l,r]内所有不同数字第一次出现的下标,输出这些下标中位

特殊:如果下标数sum为偶数个,则输出第sum/2个下标,且强制在线,每一组的l和r都跟上一组的答案有关

(HDU 5919:http://acm.hdu.edu.cn/showproblem.php?pid=5919)

输入样例:                            对应输出:

1                                            Case #1: 3 1

5 2

2 5 2 1 2

2 3

2 4


解题思路:

将数组倒过来建树,每当添加一个数字时,设这个数字的下标为i,这个数字上次出现的下标为j,则下标i对应

的val值+1,下标j对应的val值-1,每次查询区间[l,r]直接询问版本为l的树即可,先找出在这个区间内的val值之和

sum,然后在这个区间内找到第(sum+1)/2个值为1的下标就是答案


#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;typedef struct{int l, r;int val;}Ctree;Ctree s[8000005];int n, tot, a[200005], t[200005], flag[200005], prt[200005];int Build(int l, int r);int Update(int root, int x, int k);int Query(int root, int l, int r, int a, int b);int Find(int root, int k);int main(void){int T, i, q, l, r, ans, sum, k, temp, cas = 1;scanf("%d", &T);while(T--){ans = tot = 0;memset(flag, -1, sizeof(flag));scanf("%d%d", &n, &q);for(i=1;i<=n;i++)scanf("%d", &a[i]);t[n+1] = Build(1, n);for(i=n;i>=1;i--){t[i] = Update(t[i+1], i, 1);if(flag[a[i]]!=-1)t[i] = Update(t[i], flag[a[i]], -1);/*直接另起一棵树,虽然有点浪费空间*/flag[a[i]] = i;}k = 0;while(q--){scanf("%d%d", &l, &r);temp = l;l = min((l+ans)%n+1, (r+ans)%n+1);r = max((temp+ans)%n+1, (r+ans)%n+1);sum = Query(t[l], 1, n, l, r);ans = Find(t[l], (sum+1)/2);prt[++k] = ans;}printf("Case #%d:", cas++);for(i=1;i<=k;i++)printf(" %d", prt[i]);printf("\n");}return 0;}int Build(int l, int r)/*建空树,所有节点val值为0*/{int m, root;m = (l+r)/2;root = ++tot;if(l==r){s[root].val = 0;return root;}s[root].l = Build(l, m);s[root].r = Build(m+1, r);s[root].val = s[s[root].l].val+s[s[root].r].val;return root;}int Update(int root, int x, int k)/*修改第x个下标的值*/{int now, temp, m, l, r;temp = now = ++tot;l = 1, r = n;while(l<r){m = (l+r)/2;s[now].val = s[root].val+k;if(x<=m){s[now].l = ++tot;s[now].r = s[root].r;root = s[root].l;r = m;now = tot;}else{s[now].l = s[root].l;s[now].r = ++tot;root = s[root].r;l = m+1;now = tot;}}s[now].val = s[root].val+k;return temp;}int Query(int root, int l, int r, int a, int b){int m, sum;if(l>=a && r<=b)return s[root].val;m = (l+r)/2;sum = 0;if(a<=m)sum += Query(s[root].l, l, m, a, b);if(b>=m+1)sum += Query(s[root].r, m+1, r, a, b);return sum;}int Find(int root, int k){int l, r, m;l = 1, r = n;while(l<r){m = (l+r)/2;if(s[s[root].l].val>=k){root = s[root].l;r = m;}else{k -= s[s[root].l].val;root = s[root].r;l = m+1;}}return l;}


1 0
原创粉丝点击