HDU 3727 划分树



Jewel

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1005    Accepted Submission(s): 249


Problem Description
Jimmy wants to make a special necklace for his girlfriend. He bought many beads with various sizes, and no two beads are with the same size. Jimmy can't remember all the details about the beads, for the necklace is so long. So he turns to you for help.

Initially, there is no bead at all, that is, there is an empty chain. Jimmy always sticks the new bead to the right of the chain, to make the chain longer and longer. We number the leftmost bead as Position 1, and the bead to its right as Position 2, and so on. Jimmy usually asks questions about the beads' positions, size ranks and actual sizes. Specifically speaking, there are 4 kinds of operations you should process:

Insert x
Put a bead with size x to the right of the chain (0 < x < 231, and x is different from all the sizes of beads currently in the chain)
Query_1 s t k
Query the k-th smallest bead between position s and t, inclusive. You can assume 1 <= s <= t <= L, (L is the length of the current chain), and 1 <= k <= min (100, t-s+1)
Query_2 x
Query the rank of the bead with size x, if we sort all the current beads by ascent order of sizes. The result should between 1 and L (L is the length of the current chain)
Query_3 k
Query the size of the k-th smallest bead currently (1 <= k <= L, L is the length of the current chain)

 

Input
There are several test cases in the input. The first line for each test case is an integer N, indicating the number of operations. Then N lines follow, each line contains one operation, as described above.

You can assume the amount of "Insert" operation is no more than 100000, and the amounts of "Query_1", "Query_2" and "Query_3" are all less than 35000.
There are several test cases in the input. The first line for each test case is an integer N, indicating the number of operations. Then N lines follow, each line contains one operation, as described above.

You can assume the amount of "Insert" operation is no more than 100000, and the amounts of "Query_1", "Query_2" and "Query_3" are all less than 35000.Query the rank of the bead with size x, if we sort all the current beads by ascent order of sizes. The result should between 1 and L (L is the length of the current chain)
Query_3 k
Query the size of the k-th smallest bead currently (1 <= k <= L, L is the length of the current chain)

 

Output
Output 4 lines for each test case. The first line is "Case T:", where T is the id of the case. The next 3 lines indicate the sum of results for Query_1, Query_2 and Query_3, respectively.

 

Sample Input
  
  
10 Insert 1 Insert 4 Insert 2 Insert 5 Insert 6 Query_1 1 5 5 Query_1 2 3 2 Query_2 4 Query_3 3 Query_3 1
 

Sample Output
  
  
Case 1: 10 3 5
Hint
The answers for the 5 queries are 6, 4, 3, 4, 1, respectively.
 

Source


题意:
初始时有一个空数列,现共有4 种操作,分别是:
1. Insert x 将x 插入到数列的右边,题目保证插入的数中没有相同的2. Query1 s t k 询问当前数列中,
区间[s, t] 内的第k 小值3. Query2 x 询问值为x 的元素在当前数列中的排名4. Query3 k 询问当前数列中
第k 小值为多少
现在给出一系列操作,最后分别求出所有Query 操作的和并输出
分析:
题目看似是一系列动态操作,似乎要在线处理,但仔细分析发现insert 操作每次都在数列右边插入元素,
而对前面的元素排列没有影响,于是考虑离线处理,记录Query2 和Query3 时,应该还要记录当前已经插
入了多少个数,在之后处理的过程中就能确定询问的区间。这样就能用划分树来解决问题了。
离线处理后利用所有元素构造划分树,Query1 和Query3 其实就是裸的区间第k 大,直接套用模板。
Query2 只要稍将划分树的Query 操作稍加变形就能解决。每次判断x 是进入左子树还是右子树,如果进入
右子树,就把询问的区间内进入左子树的数的个数相加。

代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <stack>
#include <cmath>
#include <queue>
#include <string>
#include <cstring>
#include <map>
using namespace std;

#define MAXN 100010
#define INF 0x7fffffff

class Tree
{
public:
    int num[MAXN], val[MAXN];
};
Tree tree[20];

class Q
{
public:
    int type;
    int l, r, k, x;
    int num;
};
Q q[120010];
int n, val[MAXN], cnt, leftnum;
char str[50];

void build(int, int, int);
int query_2(int x);
int query_3(int k, int r);

void init()
{
    for(int i = 1; i < cnt; i++)
    {
        tree[0].val[i] = val[i];
    }
    sort(val+1, val+cnt);
    build(0, 1, cnt-1);
}

void build(int dep, int l, int r)
{
    int lsame = 0, mid = (l+r)>>1, lcnt = l, rcnt = mid+1;
    for(int i = l; i <= mid; i++)
    {
        if(val[i] == val[mid]) lsame++;
    }
    for(int i = l; i <= r; i++)
    {
        if(i == l)
        {
            tree[dep].num[i] = 0;
        }
        else
        {
            tree[dep].num[i] = tree[dep].num[i-1];
        }
        if(tree[dep].val[i] < val[mid])
        {
            tree[dep].num[i]++;
            tree[dep+1].val[lcnt++] = tree[dep].val[i];
        }
        else if(tree[dep].val[i] > val[mid])
        {
            tree[dep+1].val[rcnt++] = tree[dep].val[i];
        }
        else
        {
            if(lsame-- > 0)
            {
                tree[dep].num[i]++;
                tree[dep+1].val[lcnt++] = tree[dep].val[i];
            }
            else
            {
                tree[dep+1].val[rcnt++] = tree[dep].val[i];
            }
        }
    }

    if(l == r)
    {
        return;
    }

    build(dep+1, l, mid);
    build(dep+1, mid+1, r);
}
int query_1(int dep, int l, int r, int a, int b, int k)
{
    if(l == r) return tree[dep].val[l];

    int la, lb = tree[dep].num[b], mid = (l+r)>>1;
    if(a == l) la = 0;
    else la = tree[dep].num[a-1];

    if(lb-la >= k)
    {
        return query_1(dep+1, l, mid, l+la, l+lb-1, k);
    }
    else
    {
        int rx = a-l-la, ry = b-a+1-lb+la;
        return query_1(dep+1, mid+1, r, mid+1+rx, mid+rx+ry, k-lb+la);
    }
}
void q2(int dep, int l, int r, int a, int b, int x)
{
    if(l == r) return;
    int mid = (l+r)>>1;
    int la = l == a ? 0 : tree[dep].num[a-1], lb = tree[dep].num[b];

    if(x <= val[mid])
    {
        q2(dep+1, l, mid, l+la, l+lb-1, x);
    }
    else
    {
        int rx = a-l-la, ry = b-a+1-lb+la;
        leftnum += lb-la;
        q2(dep+1, mid+1, r, mid+1+rx, mid+rx+ry, x);
    }
}
int query_2(int x, int r)
{
    leftnum = 0;
    q2(0, 1, cnt-1, 1, r, x);
    return leftnum+1;
}
int query_3(int k, int r)
{
    return query_1(0, 1, cnt-1, 1, r, k);
}

int main()
{
	//freopen("C:\\Users\\zts\\Desktop\\in.txt", "r", stdin);
	int l, r, k, s, x, cntq, cas = 0;
	while(scanf("%d", &n) != -1)
    {
        cnt = 1, cntq = 0;

        for(int i = 0; i < n; i++)
        {
            scanf(" %s", str);

            if(str[0] == 'I')
            {
                scanf("%d", &x);
                val[cnt++] = x;
            }
            else if(str[6] == '1')
            {
                q[cntq].type = 1;
                scanf("%d%d%d", &q[cntq].l, &q[cntq].r, &q[cntq].k);
                cntq++;
            }
            else if(str[6] == '2')
            {
                q[cntq].type = 2;
                q[cntq].num = cnt;
                scanf("%d", &q[cntq].x);
                cntq++;
            }
            else
            {
                q[cntq].type = 3;
                q[cntq].num = cnt;
                scanf("%d", &q[cntq].k);
                cntq++;
            }
        }
        init();
        printf("Case %d:\n", ++cas);
        long long ans[3];
        ans[0] = ans[1] = ans[2] = 0;
        for(int i = 0; i < cntq; i++)
        {
            if(q[i].type == 1)
            {
                ans[0] += query_1(0, 1, cnt-1, q[i].l, q[i].r, q[i].k);
            }
            else if(q[i].type == 2)
            {
                ans[1] += query_2(q[i].x, q[i].num-1);
            }
            else
            {
                ans[2] += query_3(q[i].k, q[i].num-1);
            }
        }
        for(int i = 0; i < 3; i++)
            printf("%I64d\n", ans[i]);
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值