区间查询问题

问题:In your childhood, do you crazy for collecting the beautiful cards in the snacks? They said that, for example, if you collect all the 108 people in the famous novel Water Margin, you will win an amazing award.

As a smart boy, you notice that to win the award, you must buy much more snacks than it seems to be. To convince your friends not to waste money any more, you should find the expected number of snacks one should buy to collect a full suit of cards.
 
Input
The first line of each test case contains one integer N (1 <= N <= 20), indicating the number of different cards you need the collect. The second line contains N numbers p1, p2, ..., pN, (p1 + p2 + ... + pN <= 1), indicating the possibility of each card to appear in a bag of snacks.

Note there is at most one card in a bag of snacks. And it is possible that there is nothing in the bag.
 
Output
Output one number for each test case, indicating the expected number of bags to buy to collect all the N different cards.

You will get accepted if the difference between your answer and the standard answer is no more that 10^-4.

Sample Input
1
0.1
2
0.1 0.4

Sample Output
10.000
10.500

回答:题意:
给你 n个点。他们有 上下级关系,一个点只有一个上级,一个上级 可以有多个下级,每个点有两个属性,能力值 、忠诚度(每个节点的忠诚度不同),求我们要删除 一个节点, 则我们 需从 其下级中选出 一个节点,其能力值 比该节点 要高,且忠诚度是(比其能力高的下级节点中的)最高
题解:
首先将树状结构,转化为线状结构,
可以遍历一遍将树上每个点标记为一维区间上的某个点,且在同一棵子树内的点是连续的一段。
然后,将所有点按能力从大到小排序,能力相同的编号小的排在前面,然后扫描一遍,扫描时维护一颗线段树,
(我们先插入线段树的是,比其能力值 大的,我们只要从这些里面找到,忠诚度最高的就可以了)
先查找该点为根节点的子树内的最优值,然后插入该点的忠诚度。
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define maxn    100110
#define mod 100000007
#define eps  1e-6;
#define ll  long long
#define M   15520
using namespace std;
map<int,int>map1;
vector<int>g[maxn] ;
int num ,ans[maxn],n,m,l[maxn],r[maxn];
struct staff
{
    int loy;
    int abt;
    int id;
}sta[maxn];
struct node
{
    int l;
    int r;
    int mx;
}p[maxn * 2];
bool cmp (staff a, staff b)
{
    return a.abt > b.abt ;
}
void dfs(int x)//编号变为线状结构
{
    l[x] = num++;
    for(int i = 0; i < g[x].size(); ++i)
    {
        dfs(g[x][i]);
    }
    r[x] = num ;
}
void build(int x,int l,int r)
{
    p[x].l = l;
    p[x].r = r;
    p[x].mx = -1 ;
    if(l == r) return  ;
    int mid = (l + r) /2;
    build(x*2,l,mid);
    build(x*2+1,mid + 1,r);
}
int get(int x,int l,int r)
{
    if( r < l ) return  -1 ;
    if(p[x].l == l && p[x].r == r)
    {
        return p[x].mx;
    }
    int mid = (p[x].l + p[x].r) /2 ;
    if(r <= mid)  return get(x * 2,l,r);
    else
    {
        if(l > mid) return get(x * 2 + 1,l,r);
        else
        {
            return max(get(x * 2,l,mid),get(x * 2 + 1,mid + 1,r));
        }
    }
}
void insert(int x,int pos,int d)
{
    if(p[x].l == p[x].r )
    {
        p[x].mx = d;
        return ;
    }
    int mid = (p[x].l + p[x].r) /2 ;
    if(pos <= mid) insert(x*2,pos,d);
    else
    {
        insert(x*2 + 1, pos,d);
    }
    p[x].mx = max(p[x*2].mx,p[x*2+1].mx);
}
void init()
{
    for( int i = 0; i <= n; ++i )
        g[i].clear();
    map1.clear();
    num = 0 ;
}
int main()
{
    int t,u,loy,abt,a,j,i;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init();
        for( i = 1 ; i < n; ++i)
        {
            scanf("%d%d%d",&u,&loy,&abt);
            g[u].push_back(i);
            sta[i].loy = loy;
            sta[i].abt = abt ;
            sta[i].id = i;
            map1[loy] = i;
        }
        dfs(0);
        build(1,0,num - 1);
        sort(sta + 1,sta + n,cmp);//排序为了下面 查询 打基础,排好序之后,我们插入时,保证了,比 i 大的已经插入了这时直接找,忠诚的uida就可以了
        for( i = 1 ; i < n ; i = j)
        {
            j = i;
            while(j < n &&sta[i].abt == sta[j].abt)
            {
                int id = sta[j].id ;
                loy = get(1,l[id] + 1,r[id] - 1);

if(loy != -1) ans[id] = map1[loy] ;
                else ans[id] = -1;
                ++j;
            }
            j = i ;
            while(j < n && sta[i].abt == sta[j].abt )
            {
                int id =  sta[j].id;
                insert(1,l[id],sta[j].loy);
                ++j;
            }
        }
        while(m--)
        {
            scanf("%d",&a);
            printf("%d\n",ans[a]) ;
        }
    }
    return 0;
}

时间: 2024-11-03 21:11:03

区间查询问题的相关文章

poj3667(并查集区间合并&amp;区间查询)

题目链接: http://poj.org/problem?id=3667 题意:第一行输入 n, m表示有 n 间房间(连成一排的), 接下来有 m 行输入, 对于接下来的 m 行输入: 1 x : 询问是否有长度为 x 的连号空房, 若有, 住进最左边并输出对应编号: 2 x y : 将区间 [x, x + y - 1] 的房间清空: 思路: 并查集区间合并&区间查询 下面一段题解摘自: http://www.cnblogs.com/scau20110726/archive/2013/05/0

【算法系列学习】线段树vs树状数组 单点修改,区间查询 [kuangbin带你飞]专题七 线段树 A - 敌兵布阵

https://vjudge.net/contest/66989#problem/A 单点修改,区间查询 方法一:线段树 http://www.cnblogs.com/kuangbin/archive/2011/08/15/2139834.html 1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<cmath> 6 #

!POJ 2352 左下角星星-线段树-(单点更新,区间查询)

题意:直接坐标系中有n个星星,每个星星左下角的星星个数是它的价值,输出价值为0~n-1的星星个数. 分析: 这题就没有上面四道线段树的题裸了. 这题是怎么联系到区间,然后用线段树维护的呢? 因为题目要求输入的次序是按y第一关键字,x第二关键字升序输入,那么我们可以想到对于星星A(x,y),它左下角的星星一定在比他先输入的星星中,所以我们只需判断在比他先输入的星星的x2,如果x2<=x,那么星星A的价值+1.所以这题就转化为了求区间中的tot[0~x],也就是区间查询.每输入一个星星,先在原来的树

HDU 4027 Can you answer these queries?(线段树,区间更新,区间查询)

题目 线段树 简单题意: 区间(单点?)更新,区间求和 更新是区间内的数开根号并向下取整 这道题不用延迟操作 //注意: //1:查询时的区间端点可能前面的比后面的大: //2:优化:因为每次更新都是开平方,同一个数更新有限次数就一直是1了,所以可以这样优化 #include <stdio.h> #include<math.h> #define N 100010 #define LL __int64 #define lson l,m,rt<<1 #define rson

Wikioi 2492 树状数组+并查集(单点更新区间查询)

刚开始做的时候用线段树做的,然后就跳进坑里了--因为要开方,所以区间的值都得全部变,然后想用lazy标记的,但是发现用不了,单点更新这个用不了,然后就不用了,就T了.然后实在不行了,看了别人的题解,原来是用树状数组+并查集的方法,唉--没想到啊! 因为开方之后多次那个数就会变成1了,所以是1的时候开方下去就没用了.树状数组更新的时候就把其更新的差更新即可,太机智了这题-- 昨天做了,然后出错找了好久都找不出来,原来是把s[i]写成c[i]了,然后答案一直错,晕-- #include <iostr

HDU 1754 - I Hate It &amp; UVA 12299 - RMQ with Shifts - [单点/区间修改、区间查询线段树]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1754 Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.这让很多学生很反感.不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老师

BinaryIndexTree(一):单点更新,区间查询

背景: 树状数组(Binary Index Tree)是一种处理区间问题较为容易实现的数据结构,可以处理单点更新,区间更新,单点查询,区间查询等问题,是一种处理在线问题的利器,其查询跟修改的时间复杂度均为O(logn). 引入: 在算法竞赛中经常会遇到这样一类问题:给定一个数列,让你求出这个序列的某个数及其之前的数的和.通常最暴力的做法,求x位置及其之前的数的和,就是从第一个数开始依次扫到x位置,这样对于一次的查询当然没什么大问题,那么对于多次的查询,复杂度就是O(query * positio

tyvj P1716 - 上帝造题的七分钟 二维树状数组区间查询及修改 二维线段树

P1716 - 上帝造题的七分钟 From Riatre    Normal (OI)总时限:50s    内存限制:128MB    代码长度限制:64KB 背景 Background 裸体就意味着身体. 描述 Description “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵.第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作.第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作.第

树状数组的区间修改与单点查询与区间查询

如何将普通树状数组升级 普通的单点修改单点查询就不讲了,从区间修改和单点查询讲起. 原来的值存在a[]里面,多建立个数组c1[],注意:c1[i]=a[i]-a[i-1]. 那么求a[i]的值的时候a[i]=a[i-1]+c1[i]=a[i-2]+c1[i]+c1[i-1]=-..=c1[1]+c1[2]+-+c1[i]. 所以就用c1[]建立树状数组,便可以很快查询a[i]的值.不多说,见代码. #include<iostream> #include<cstdio> #defin

数据结构--M - 秋实大哥与线段树(单点更新与区间查询)

M - 秋实大哥与线段树 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status “学习本无底,前进莫徬徨.” 秋实大哥对一旁玩手机的学弟说道. 秋实大哥是一个爱学习的人,今天他刚刚学习了线段树这个数据结构. 为了检验自己的掌握程度,秋实大哥给自己出了一个题,同时邀请大家一起来作. 秋实大哥的题目要求你维护一个序列,支持两种操作:一种是修改某一个元素的值:一