博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDU 5919 Sequence II(主席树)题解
阅读量:5337 次
发布时间:2019-06-15

本文共 2596 字,大约阅读时间需要 8 分钟。

题意:有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个不同的数字下标是多少?

思路:显然是个在线询问。

我们之前已经会用主席树求区间内有多少不同数字了:从左到右把每个数字的位置存进每个操作的线段树,如果之前这个数已经出现,就在当前这棵线段树中删掉之前出现的位置,以保证每个数字出现的唯一性。显然每个区间保存的是某个数字最右边出现的位置。

但是这里显然我们不能去直接求第(k + 1)/ 2个不同的数字下标,因为我这里要求的是最早出现第(k + 1)/ 2个数的位置。那我直接从n往1建主席树,那我就变成了每个区间保存的是某个数字最左边出现的位置,显然我第i棵树并没有保存i前面的位置,那我就可以直接求i到后面任意位置的区间的第p个不相同数出现的位置。

代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;typedef long long ll;typedef unsigned long long ull;const int maxn = 2e5 + 10;const int M = maxn * 30;const ull seed = 131;const int INF = 0x3f3f3f3f;const int MOD = 1000000007;int a[maxn], root[maxn], tot;int n, q;struct node{ int lson, rson; int sum;}T[maxn * 40];int fa[maxn], ans[maxn];void init(){ tot = 0; memset(fa, -1, sizeof(fa)); memset(T, 0, sizeof(T));}void update(int l, int r, int &now, int pre, int pos, int v){ T[++tot] = T[pre], now = tot; T[now].sum += v; if(l == r) return; int m = (l + r) >> 1; if(pos <= m) update(l, m, T[now].lson, T[pre].lson, pos, v); else update(m + 1, r, T[now].rson, T[pre].rson, pos, v);}int query1(int l, int r, int L, int R, int now){ if(L <= l && R >= r){ return T[now].sum; } int m = (l + r) >> 1, sum = 0; if(L <= m) sum += query1(l, m, L, R, T[now].lson); if(R > m) sum += query1(m + 1, r, L, R, T[now].rson); return sum;}int query2(int l, int r, int now, int k){ if(l == r) return l; int m = (l + r) >> 1; int sum = T[T[now].lson].sum; if(sum >= k) return query2(l, m, T[now].lson, k); else return query2(m + 1, r, T[now].rson, k - sum);}int main(){ int ca = 1, t; scanf("%d" ,&t); while(t--){ init(); scanf("%d%d", &n, &q); root[n + 1] = 0; for(int i = 1; i <= n; i++) scanf("%d", &a[i]); for(int i = n; i >= 1; i--){ if(fa[a[i]] == -1){ update(1, n, root[i], root[i + 1], i, 1); fa[a[i]] = i; } else{ update(1, n, root[i], root[i + 1], i, 1); update(1, n, root[i], root[i], fa[a[i]], -1); fa[a[i]] = i; } } ans[0] = 0; for(int i = 1; i <= q; i++){ int l, r, L, R, k; scanf("%d%d", &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); k = query1(1, n, L, R, root[L]); ans[i] = query2(1, n, root[L], (k + 1) / 2); } printf("Case #%d:", ca++); for(int i = 1 ; i <= q; i++) printf(" %d", ans[i]); printf("\n"); } return 0;}

 

转载于:https://www.cnblogs.com/KirinSB/p/10786248.html

你可能感兴趣的文章
egret3D与2D混合开发,画布尺寸不一致的问题
查看>>
struts1和struts2的区别
查看>>
Redis常用命令
查看>>
2019.02.15 bzoj5210: 最大连通子块和(链分治+ddp)
查看>>
微软职位内部推荐-Sr. SE - Office incubation
查看>>
C#类与结构体究竟谁快——各种函数调用模式速度评测
查看>>
我到底要选择一种什么样的生活方式,度过这一辈子呢:人生自由与职业发展方向(下)...
查看>>
poj 题目分类
查看>>
windows 安装yaml支持和pytest支持等
查看>>
读书笔记:季羡林关于如何做研究学问的心得
查看>>
面向对象的优点
查看>>
套接口和I/O通信
查看>>
阿里巴巴面试之利用两个int值实现读写锁
查看>>
浅谈性能测试
查看>>
Winform 菜单和工具栏控件
查看>>
CDH版本大数据集群下搭建的Hue详细启动步骤(图文详解)
查看>>
巧用Win+R
查看>>
浅析原生js模仿addclass和removeclass
查看>>
Python中的greenlet包实现并发编程的入门教程
查看>>
java中遍历属性字段及值(常见方法)
查看>>