POJ 2828 poj 2828 Buy Tickets 【树状数组,已知前n项和为K,返回n值】

题目链接:http://poj.org/problem?id=2828

在一个队列中,一个人想要插队,告诉你每个新来的人会插在i个人后面,求出最后的队列。

如果我们用模拟的话,那么时间复杂度肯定是超了;想想,如果我们逆序,那么最后来的人的位置一定是固定的,这样的话,我们将问题转化成逆序扫描给出数据,插在i个人后面这个数据就变成了在这个人前面需要留出多少个空位。如此我们只需要用树状数组记录前n项总共有多少个空位,每扫描一个数据,就找出能使得他前面正好有i个空位。

这题用树状数组或者线段树都可以,今天写了树状数组的。开始不知道有那个已知前n项和为K,返回n值的函数,就用二分查找了那个值,差点就T了,后来改用那个函数,节省了差不多一秒种。

代码(二分):

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define N 200020
using namespace std;
int n;
int a[N];
int c[N];
int ans[N];
struct fuck
{
    int x,num;
}peo[N];
int add(int x,int a)
{
    for(int i=x;i<=n;i+=(i&(-i)))
    {
        c[i]+=a;
    }
}
int getsum(int i)
{
    int cnt=0;
    while(i>=1)
    {
        cnt+=c[i];
        i-=(i&(-i));
    }
    return cnt;
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=n;i>=1;i--)
        {
            scanf("%d%d",&peo[i].x,&peo[i].num);
            add(i,1);
        }
        for(int i=1;i<=n;i++)
        {
            int temp=peo[i].x;
            int lb=0,ub=n+1;
            while(ub-lb>1)
            {
                int mid=(ub+lb)/2;
                if(getsum(mid)>temp)
                    ub=mid;
                else
                    lb=mid;
            }
            add(ub,-1);
            ans[ub]=peo[i].num;
        }
        for(int i=1;i<=n;i++)
            printf("%d%c",ans[i]," \n"[i==n]);
    }
    return 0;
}

使用那个函数的代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define N 200020
using namespace std;
int n;
int a[N];
int c[N];
int ans[N];
struct fuck
{
    int x,num;
}peo[N];
int add(int x,int a)
{
    for(int i=x;i<=n;i+=(i&(-i)))
    {
        c[i]+=a;
    }
}
int getsum(int i)
{
    int cnt=0;
    while(i>=1)
    {
        cnt+=c[i];
        i-=(i&(-i));
    }
    return cnt;
}
int getK(int K)
{
    int ans = 0,cnt=0;
    for(int i=18;i>=0;i--)//i>=0
    {
        ans+=(1<<i);
        if(ans>=n||cnt+c[ans]>=K) ans-=(1<<i);
        else cnt+=c[ans];
    }
    return ans+1;
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&peo[i].x,&peo[i].num);
            add(i,1);
        }
        for(int i=n;i>=1;i--)
        {
            int temp=peo[i].x;
//            int lb=0,ub=n+1;
//            while(ub-lb>1)
//            {
//                int mid=(ub+lb)/2;
//                if(getsum(mid)>temp)
//                    ub=mid;
//                else
//                    lb=mid;
//            }
            int ub=getK(temp+1);
            ans[ub]=peo[i].num;
            add(ub,-1);
        }
        for(int i=1;i<=n;i++)
            printf("%d%c",ans[i]," \n"[i==n]);
    }
    return 0;
}

POJ 2828 poj 2828 Buy Tickets 【树状数组,已知前n项和为K,返回n值】

时间: 2024-10-04 04:14:43

POJ 2828 poj 2828 Buy Tickets 【树状数组,已知前n项和为K,返回n值】的相关文章

poj 2828 Buy Tickets(树状数组 | 线段树)

题目链接:poj 2828 Buy Tickets 题目大意:给定N,表示有个人,给定每个人站入的位置,以及这个人的权值,现在按队列的顺序输出每个人的权值. 解题思路:第K大元素,很巧妙,将人入队的顺序倒过来看,就是纯第K大问题,然后用树状数组还是线段树就都可以做了. C++ 线段树 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn

POJ2828 Buy Tickets[树状数组第k小值 倒序]

Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 19012   Accepted: 9442 Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue… The Lunar New Year wa

POJ2828 Buy Tickets 树状数组

Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue… The Lunar New Year was approaching, but unluckily the Little Cat still had schedules going here and there. Now, he ha

POJ 2155 Matrix 【二维树状数组】

题目链接:http://poj.org/problem?id=2155 题目大意:给出一个N*N的0矩阵,下面给出两种指令:1. 给出的第一个数据为'C',再给出四个整形数据,x1,y1,y1,y2,对以(x1,y1)(x2,y2)分别为左上角和右下角坐标的矩阵内的元素进行反转(0变1,1变0)         2. 给出的第一个数据为'Q',再给出两个数据,x,y,然后输出此时这个坐标上的元素. 这题用二维树状数组解,树状数组能够对某区间更新所有元素的和,树状数组维护的是c[1][1]到c[i

【poj 2892】Tunnel Warfare 二分+树状数组

Tunnel Warfare Time Limit: 1000MS Memory Limit: 131072K Total Submissions: 7576 Accepted: 3127 Description During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaki

POJ 2155 Matrix【二维树状数组+YY(区间更新,单点查询)】

题目链接:http://poj.org/problem?id=2155 Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 32950   Accepted: 11943 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th col

POJ - 2299 - Ultra-QuickSort = 归并排序 + 逆序对 / 树状数组

http://poj.org/problem?id=2299 求逆序对最简单的绝对不会是树状数组,一定是归并排序(认真),不过树状数组会不会快一点呢?理论上应该是树状数组快一点(假如不进行离散化). #include<algorithm> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<map> #include<set

POJ 2155 Matrix(二维树状数组)

题意:有一个矩阵,每次操作可以是编辑某个矩形区域,这个区域的0改为1,1改为0,每次查询只查询某一个点的值是0还是1.  思路:这道题和一般的树状数组有一点不同,这道题是区间修改,单点查询,而树状数组处理的是单点修改,所以我们可以改一下矩阵里的每一个值代表的意义.可以注意到我们只关注一个点被翻转了奇数次还是偶数次,令矩阵的元素a[i][j]表示矩形区域(1,1)到(i,j)的修改次数,这样我们可以把区间修改转化为四个端点的单点修改,即modify(x2, y2, 1); modify(x1-

POJ 3321 Apple Tree DFS序 + 树状数组

多次修改一棵树节点的值,或者询问当前这个节点的子树所有节点权值总和. 首先预处理出DFS序L[i]和R[i] 把问题转化为区间查询总和问题.单点修改,区间查询,树状数组即可. 注意修改的时候也要按照dfs序修改,因为你查询就是按照dfs查的,所以修改也要用dfs序修改 L[i]是唯一的. #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <