UVa1480/LA5034 Jewel

UVa1480/LA5034 Jewel

题目链接

本题是2010年icpc亚洲区域赛天津赛区J

题意

Jimmy买了很多颗大小互不相同的珠子用来穿成项链送给他的女朋友,初始时项链是空的。Jimmy会进行4种操作:

操作 说明
Insert x 将尺寸为x的珠子穿到项链的尾部
Query_1 s t k 查询位置在[s,t]区间中第k小珠子的尺寸
Query_2 x 查询当前项链串中尺寸为x的珠子的排名
Query_3 k 查询当前项链串中排名为k的珠子的尺寸

输入格式

多组输入,每组数据第一行是一个整数 N ,表示操作的总数,接下来 N 行每行描述各个操作。每组数据 Insert 总数不超过 100000,Query_1、Query_2 和 Query_3 每类的总数都小于 35000。

输出格式

对每组数据输出4行,第一行为"Case T:"(其中T是数据的id),接下来 3 行依次是 Query_1、Query_2 和 Query_3 每类的结果总和。

分析

如果没有Query_1,那么直接用名次树就行了:每次往名次树插入 x 或者查询 kth(k)、rank(x)。为了解决 Query_1 还是要上线段树 ,需要用到"前缀"思想(每个 Insert 操作对应一棵线段树,并且是在前一棵线段树基础上更新得到的),并且按题目交代的数据规模需要动态开点。同名次树一样,线段树每个节点维护其区间内的附加域 size。

把所有 Insert x i x_i xi 操作的 M 个数放到数组里面做一次排序,可以得到每个每个 x i x_i xi 的最终位置 p [ x i ] p[x_i] p[xi],然后再依次处理各个操作:对每个 Insert x i x_i xi 初始化其线段树 s t [ i ] st[i] st[i] 为上一棵线段树 s t [ i − 1 ] st[i-1] st[i−1],然后从线段树根结点到 p [ x i ] p[x_i] p[xi] 所在的叶结点路径上每个结点的 size 做更新(具体来说,根节点 o 对应区间 [1,M],其 size 增加1,记 m i d = ( 1 + M ) / 2 mid = (1+M)/2 mid=(1+M)/2,若 p [ x i ] p[x_i] p[xi] 在 [1,mid] 区间,则递归更新左子树 lc[o] ------ 对应区间 [1,mid],否则递归更新右子树 rc[o] ------ 对应区间 [mid+1,M]);对每个 Query_1 s t k,拿 s t [ s − 1 ] st[s-1] st[s−1] 和 s t [ t ] st[t] st[t] 这两棵线段树做联合查询能得到答案(参见 AC 代码的 kth 方法);对每个 Query_2 x,记当前线段树是第 c 棵, 拿 s t [ c ] st[c] st[c] 做 rank 查询(参见 AC 代码的 rnk 方法);Query_3 k 是 Query_1 的特列(记当前线段树是第 c 棵,则为 Query_1 1 c k)。

AC 代码

cpp 复制代码
#include <iostream>
#include <algorithm>
using namespace std;

#define N 103000
#define T 18*N
struct {int e, s, t, x;} op[2*N]; int a[N], st[N], lc[T], rc[T], s[T], m, n, t, kase = 0; char e[8];

void update(int& o, int pre, int l, int r, int x) {
    int m = (l+r)>>1; o = ++t; lc[o] = lc[pre]; rc[o] = rc[pre]; s[o] = s[pre]+1;
    if (l == r) return;
    x <= m ? update(lc[o], lc[pre], l, m, x) : update(rc[o], rc[pre], m+1, r, x);
}

int kth(int o, int pre, int l, int r, int k) {
    if (l == r) return a[l];
    int c = s[lc[o]] - s[lc[pre]], m = (l+r) >> 1;
    return k <= c ? kth(lc[o], lc[pre], l, m, k) : kth(rc[o], rc[pre], m+1, r, k-c);
}

int rnk(int o, int l, int r, int x) {
    if (l == r) return 1;
    int m = (l+r)>>1;
    return x <= m ? rnk(lc[o], l, m, x) : s[lc[o]] + rnk(rc[o], m+1, r, x);
}

void solve() {
    for (int i=m=t=0; i<n; ++i) {
        cin >> e; op[i].e = e[0]=='I' ? 0 : e[6]-'0';
        op[i].e == 1 ? cin >> op[i].s >> op[i].t >> op[i].x : cin >> op[i].x;
        if (op[i].e == 0) a[++m] = op[i].x;
    }
    sort(a+1, a+m+1);
    long long q1 = 0, q2 = 0, q3 = 0;
    for (int i=0, c=0; i<n; ++i) {
        if (op[i].e == 0) ++c, update(st[c], st[c-1], 1, m, lower_bound(a+1, a+m+1, op[i].x)-a);
        else if (op[i].e == 1) q1 += kth(st[op[i].t], st[op[i].s-1], 1, m, op[i].x);
        else if (op[i].e == 2) q2 += rnk(st[c], 1, m, lower_bound(a+1, a+m+1, op[i].x)-a);
        else q3 += kth(st[c], st[0], 1, m, op[i].x);
    }
    cout << "Case " << ++kase << ':' << endl << q1 << endl << q2 << endl << q3 << endl;
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    st[0] = lc[0] = rc[0] = s[0] = 0;
    while (cin >> n) solve();
    return 0;
}
相关推荐
Estella-Ealine9 天前
5.10 周赛vp 2026 ICPC Gran Premio de Mexico 1ra Fecha E题
icpc·2026
所以遗憾是什么呢?10 天前
【题解】Codeforces Round 1097 (Div. 2, Based on Zhili Cup 2026) (致理杯) ABCDEF
数据结构·算法·acm·codeforces·icpc·ccpc·xcpc
漂流瓶jz17 天前
UVA-1152 和为0的4个值 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·二分查找·题解·aoapc·算法竞赛入门经典·uva
AKDreamer_HeXY18 天前
QOJ 12255 - 36 Puzzle 题解
数据结构·c++·数学·算法·icpc·qoj
漂流瓶jz1 个月前
UVA-120 煎饼 题解答案代码 算法竞赛入门经典第二版
数据结构·c++·算法·排序·aoapc·算法竞赛入门经典·uva
medal_dreams1 个月前
可持久化线段树/主席树 学习笔记
线段树·学习笔记
2401_892070981 个月前
算法与数据结构精讲:最大子段和(暴力 / 优化 / 分治)+ 线段树从入门到实战
c++·算法·线段树·最大子段和
所以遗憾是什么呢?1 个月前
【题解】Codeforces Round 1081 (Div. 2)
数据结构·c++·算法·acm·icpc·ccpc·xcpc
漂流瓶jz1 个月前
UVA-10384 推门游戏 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·深度优先·题解·aoapc·算法竞赛入门经典·uva
漂流瓶jz2 个月前
UVA-11846 找座位 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·排序算法·深度优先·aoapc·算法竞赛入门经典·uva