题目大意

给定一个大小为n,每个数的大小均在[1,c]之间的数列,你需要回答m个询问,其中第i个询问形如\((l_i, r_i)\),你需要回答是否存在一个数使得它在区间\([l_i,r_i]\)中出现至少\(\frac{r-l+1}{2}\)次。

题解

第一次写主席树。

不难发现,对于一个询问,只有可能要么有解,要么有一个解。

考虑到每个数均在一个确定的区间内,我们考虑开一棵权值线段树(以前一直用这种方法,但不知到这就是权值线段树)来记录每一个数字的出现次数。

考虑到他要求询问一个区间,我们只要知道在后一个时间点树的情况和前一个时间点的树的情况就好了。但是,我们需要修改线段树,所以我们需要使用一个可持久化数据结构来实现这种修改与查询。

具体地,我们考虑对于每次修改建一棵新树来存储这个时间点的情况。显然这个时间点可以从上一个时间点推出来。

如果我们真的建一棵新树,显然会爆空间。我们考虑仅仅在修改过的节点新建节点,同时把边乱连合理地连接即可。

对于每一个询问,我们二分答案即可。

至于复杂度,时间复杂度的话就是\(\Theta(跑得过)\),但空间复杂度就是\(\Theta(不一定能跑过)\)辣(逃

不过在bzoj改数据以后还是能过的。

注意

二分答案的时候,注意返回0的情况。也就是说,充分考虑到每一种情况并为其设立出口。

代码(bzoj3524)

#include <cstdio>
int n, m, sz;
const int maxn = 500010;
const int maxm = 10000010;
int rt[maxn], lc[maxm], rc[maxm], sum[maxm];
void update(int l, int r, int x, int &y, int v) {
y = ++sz;
sum[y] = sum[x] + 1;
if (l == r)
return;
lc[y] = lc[x];
rc[y] = rc[x];
int mid = (l + r) >> 1;
if (v <= mid)
update(l, mid, lc[x], lc[y], v);
else
update(mid + 1, r, rc[x], rc[y], v);
}
int que(int L, int R) {
int l = 1, r = n, mid, x, y, tmp = (R - L + 1) >> 1;
x = rt[L - 1];
y = rt[R];
while (l != r) {
if (sum[y] - sum[x] <= tmp)
return 0;
mid = (l + r) >> 1;
if (sum[lc[y]] - sum[lc[x]] > tmp) {
r = mid;
x = lc[x];
y = lc[y];
} else if (sum[rc[y]] - sum[rc[x]] > tmp) {
l = mid + 1;
x = rc[x];
y = rc[y];
} else
return 0;
}
return l;
}
int main() {
#ifdef D
freopen("input", "r", stdin);
#endif
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
update(1, n, rt[i - 1], rt[i], x);
}
for (int i = 1; i <= m; i++) {
int l, r;
scanf("%d %d", &l, &r);
printf("%d\n", que(l, r));
}
}

代码(bzoj2223)

#include <cstdio>
int n, m, a, sz;
const int maxn = 500010;
const int maxm = 10000010;
int rt[maxn], lc[maxm], rc[maxm], sum[maxm];
void update(int l, int r, int x, int &y, int v) {
y = ++sz;
sum[y] = sum[x] + 1;
if (l == r)
return;
lc[y] = lc[x];
rc[y] = rc[x];
int mid = (l + r) >> 1;
if (v <= mid)
update(l, mid, lc[x], lc[y], v);
else
update(mid + 1, r, rc[x], rc[y], v);
}
int que(int L, int R) {
int l = 1, r = a, mid, x, y, tmp = (R - L + 1) >> 1;
x = rt[L - 1];
y = rt[R];
while (l != r) {
if (sum[y] - sum[x] <= tmp)
return 0;
mid = (l + r) >> 1;
if (sum[lc[y]] - sum[lc[x]] > tmp) {
r = mid;
x = lc[x];
y = lc[y];
} else if (sum[rc[y]] - sum[rc[x]] > tmp) {
l = mid + 1;
x = rc[x];
y = rc[y];
} else
return 0;
}
return l;
}
int main() {
#ifdef D
freopen("input", "r", stdin);
#endif
scanf("%d %d", &n, &a);
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
update(1, a, rt[i - 1], rt[i], x);
}
scanf("%d", &m);
for (int i = 1; i <= m; i++) {
int l, r;
scanf("%d %d", &l, &r);
int ans = que(l, r);
if (ans > 0) {
printf("yes %d\n", ans);
} else
printf("no\n");
}
}

[bzoj3524==bzoj2223][Poi2014]Couriers/[Coci 2009]PATULJCI——主席树+权值线段树的更多相关文章

  1. 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题

    “队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄>     线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...

  2. [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树

    二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...

  3. BZOJ2223[Coci 2009]PATULJCI——主席树

    题目描述 输入  先输入一个数n,然后一个数表示这n个数中最大的是多少,接下来一行n个数.然后一个数m,最后m行询问每次两个数l,r. 输出 no或者yes+这个数 样例输入 10 3 1 2 1 2 ...

  4. HDU - 2665 Kth number 主席树/可持久化权值线段树

    题意 给一个数列,一些询问,问$[l,r]$中第$K$大的元素是哪一个 题解: 写法很多,主席树是最常用的一种之一 除此之外有:划分树,莫队分块,平衡树等 主席树的定义其实挺模糊, 一般认为就是可持久 ...

  5. BZOJ2141排队——树状数组套权值线段树(带修改的主席树)

    题目描述 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家 乐和和.红星幼儿园的小朋友们排起了长长地队伍,准备吃果果.不过因为小朋友们的身高有所区别 ...

  6. HDU6621 K-th Closest Distance 第 k 小绝对值(主席树(统计范围的数有多少个)+ 二分 || 权值线段树+二分)

    题意:给一个数组,每次给 l ,r, p, k,问区间 [l, r] 的数与 p 作差的绝对值的第 k 小,这个绝对值是多少 分析:首先我们先分析单次查询怎么做: 题目给出的数据与多次查询已经在提示着 ...

  7. 莫队或权值线段树 或主席树 p4137

    题目描述 有一个长度为n的数组{a1,a2,…,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. 输入格式 第一行n,m. 第二行为n个数. 从第三行开始,每行一个询问l,r. 输出格式 ...

  8. 权值线段树&&可持久化线段树&&主席树

    权值线段树 顾名思义,就是以权值为下标建立的线段树. 现在让我们来考虑考虑上面那句话的产生的三个小问题: 1. 如果说权值作为下标了,那这颗线段树里存什么呢? ----- 这颗线段树中, 记录每个值出 ...

  9. 主席树 【权值线段树】 && 例题K-th Number POJ - 2104

    一.主席树与权值线段树区别 主席树是由许多权值线段树构成,单独的权值线段树只能解决寻找整个区间第k大/小值问题(什么叫整个区间,比如你对区间[1,8]建立一颗对应权值线段树,那么你不能询问区间[2,5 ...

随机推荐

  1. 小程序如何去掉button组件的边框

    小程序获取用户授权不再支持wx.getUserInfo方法,改为用button获取,格式如下 <button class="btn btn" open-type=" ...

  2. 「日常训练」 Soldier and Traveling (CFR304D2E)

    题意 (CodeForces 546E) 对一个无向图,给出图的情况与各个节点的人数/目标人数.每个节点的人只可以待在自己的城市或走到与他相邻的节点. 问最后是否有解,输出一可行解(我以为是必须和答案 ...

  3. Linux下创建pycharm的快捷方式

    第一步:创建桌面快捷方式文件Pycharm.desktop,并打开 sudo gedit /usr/share/applications/Pycharm.desktop 第二步:在打开的文件Pycha ...

  4. Selenide 简单实现自动化测试

    Selenide 网址:http://selenide.org/ github 地址:https://github.com/codeborne/selenide Selenide 早些年一直使用,中间 ...

  5. CCF-NOIP-2018 提高组(复赛) 模拟试题(七)

    T1 Adjoin [问题描述] 定义一种合法的\(0-1\)串:串中任何一个数字都与\(1\)相邻.例如长度为$ 3 的 0-1 $串中,\(101\)是非法的,因为两边的\(1\)没有相邻的\(1 ...

  6. day02 智能合约

    上午 1>部署智能合约网络 语法 require 2>利用第三方的节点 同步到以太坊 3>智能合约部署的步骤: 1.查看区块 2.发布合约 deploy后台经历的事情:就是部署合约的 ...

  7. DFS(4)——hdu1010Tempter of the Bone

    一.题目回顾 题目链接:Tempter of the Bone Problem Description The doggie found a bone in an ancient maze, whic ...

  8. c++ 中反正单词用到了resize()

    resize(n) 调整容器的长度大小,使其能容纳n个元素.如果n小于容器的当前的size,则删除多出来的元素.否则,添加采用值初始化的元素. 题目如下: 151. Reverse Words in ...

  9. enter & keypress

    enter & keypress https://stackoverflow.com/questions/905222/enter-key-press-event-in-javascript ...

  10. request.getParameterMap() 获取表单提交的键值对 并且 也能获取动态表单的key

    Map<String,String[]> map = request.getParameterMap();Set<String> keys = map.keySet(); 获取 ...