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 px_i pxi,然后再依次处理各个操作:对每个 Insert x i x_i xi 初始化其线段树 s t i sti sti 为上一棵线段树 s t i − 1 sti-1 sti−1,然后从线段树根结点到 p x i px_i pxi 所在的叶结点路径上每个结点的 size 做更新(具体来说,根节点 o 对应区间 1,M,其 size 增加1,记 m i d = ( 1 + M ) / 2 mid = (1+M)/2 mid=(1+M)/2,若 p x i px_i pxi 在 1,mid 区间,则递归更新左子树 lco ------ 对应区间 1,mid,否则递归更新右子树 rco ------ 对应区间 mid+1,M);对每个 Query_1 s t k,拿 s t s − 1 sts-1 sts−1 和 s t t stt stt 这两棵线段树做联合查询能得到答案(参见 AC 代码的 kth 方法);对每个 Query_2 x,记当前线段树是第 c 棵, 拿 s t c stc stc 做 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;
}
相关推荐
漂流瓶jz4 天前
UVA-11491 奖品的价值 题解答案代码 算法竞赛入门经典第二版
c++·算法·图论·题解·aoapc·算法竞赛入门经典·uva
h_a_o777oah4 天前
【树论】树链剖分:将树形结构转化为线性结构以处理树上路径问题(洛谷 P3384 附C++代码模板)
数据结构·算法·线段树·acm·树链剖分·树论·重链剖分
lvwangshu5 天前
登录日志 题解
数据结构·线段树·题解·技巧·性质题·思维好题·细节题
漂流瓶jz6 天前
UVA-1610 聚会游戏 题解答案代码 算法竞赛入门经典第二版
数据结构·c++·算法·题解·aoapc·算法竞赛入门经典·uva
漂流瓶jz6 天前
UVA-12545 比特变换器 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·题解·aoapc·算法竞赛入门经典·uva·12545
惆怅客1239 天前
UVa11640 Mayor Election
dp·fft·icpc·uva·生成函数的乘法
惆怅客1239 天前
UVa1410/LA4027 Expensive Drink
线性规划·icpc·uva·单纯形算法
漂流瓶jz19 天前
UVA-1442 洞穴 题解答案代码 算法竞赛入门经典第二版
c++·算法·题解·aoapc·算法竞赛入门经典·uva
零衣贰1 个月前
The 2026 ICPC Asia East Continent Online Contest (I) 题解
c++·icpc
lvwangshu1 个月前
P5324 [BJOI2019] 删数 题解
线段树·题解·性质题