pojBuy Tickets2828线段树(队列中倒序插队)



这题开始的思路就是模拟:就像数组中插点一样,每一个想买票的人都想往前插队!
但是这样的话肯定TLE, 看了别人的思路之后才恍然大悟!
正解:
    将开始的正序插入,变成倒序插入,这样的话,想一想:第 i 个人想要插在 p[i]
    的位置上,那么就要保证所插入的位置之前一定要有 p[i]-1个空位!因为一定会有p[j]<p[i]
    (0<=p[j]<=j,每个人都想往前插队)
    的第j个人插在p[i]的位置的前边! 

    如果i<j; && p[i]==p[j], 倒序插入中,第j个人先插入, 那么第i个人在保证插入的位置之前有
    p[i]-1个空位的同时,又要插入到第 j 个人的后边! 


 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #define M 200005
 6 using namespace std;
 7
 8 pair<int, int>per[M];
 9 int ret[M];
10 int tree[M*4];
11 int n;
12
13 void buildT(int p, int ld, int rd){
14     if(ld==rd){
15         tree[p]=1;
16         return ;
17     }
18     int mid=(ld+rd)>>1;
19     buildT(p<<1, ld, mid);
20     buildT(p<<1|1, mid+1, rd);
21     tree[p]=tree[p<<1]+tree[p<<1|1];
22 }
23
24 void updateT(int p, int ld, int rd, int pos, int val){
25    if(ld==rd){
26       tree[p]=0;
27       ret[ld]=val;
28       return ;
29    }
30    int mid=(ld+rd)>>1;
31    if(tree[p<<1]>pos)
32       updateT(p<<1, ld, mid, pos, val);
33    else
34       updateT(p<<1|1, mid+1, rd, pos-tree[p<<1], val);
35
36    tree[p]=tree[p<<1]+tree[p<<1|1];
37 }
38
39 int main(){
40    int i;
41    while(scanf("%d", &n)!=EOF){
42       buildT(1, 1, n);
43       for(i=1; i<=n; ++i)
44          scanf("%d%d", &per[i].first, &per[i].second);
45       for(i=n; i>=1; --i)
46          updateT(1, 1, n, per[i].first, per[i].second);
47
48       printf("%d", ret[1]);
49       for(i=2; i<=n; ++i)
50          printf(" %d", ret[i]);
51       printf("\n");
52    }
53    return 0;
54 } 

pojBuy Tickets2828线段树(队列中倒序插队)

时间: 2024-10-15 12:32:30

pojBuy Tickets2828线段树(队列中倒序插队)的相关文章

POJ2528Mayor&#39;s posters 线段树,离散化技巧

题意:一个坐标轴从1~1e7,每次覆盖一个区间(li,ri),问最后可见区间有多少个(没有被其他区间挡住的) 线段树,按倒序考虑,贴上的地方记为1,每次看(li,ri)这个区间是否全是1,全是1就说明在它后面贴的把它给挡住了,否则该海报可见. 然后就愉快的MLE了.... 再看看数据范围,离散化如下,比如如果海报的左右端点如下 那图中橙色的一块的大小其实对结果没有影响,可以把他们都缩为1 最后离散化结果如下图: 代码: 1 #include <algorithm> 2 #include <

线段树(区间树)

1.基本概念 线段树,Segment tree,是一颗二叉树,树的每个节点代表一个区间[a,b].故又叫做区间树,Interval tree. 用于解决线段的并,或区间覆盖问题. 性质:线段树是平衡二叉树,最大深度为logN(N为线段树所表示区间的长度). 2.线段树API 存储结构: public class Node { public int left; public int right; public int value; public Node leftChild; public Nod

树——用二叉树构建线段树

上一博文线段树问题中,用数组表示线段树,成功AC了,本文用二叉树表示线段树,复习一下二叉树,不过下面这段用二叉树代码表示的线段树是无法AC的,因为这个代码的空间复杂度远高于上一个用结构体数组表示的空间复杂度. #include<iostream> #include<cstdlib> #include<algorithm> #include<vector> #include<list> #include<iterator> #inclu

HDU 1542 Atlantis 线段树+离散化+扫描线

题意:给出一些矩形的最上角坐标和右下角坐标,求这些矩形的面积并. NotOnlySuccess 线段树专辑中扫描线模板题,弱智的我对着大大的代码看了一下午才搞懂. 具体见思路见注释=.= #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson rt<<1,l,mid #define rson rt<<1|1,mid

笔试算法题(42):线段树(区间树,Interval Tree)

议题:线段树(Interval Tree) 分析: 线段树是一种二叉搜索树,将一个大区间划分成单元区间,每个单元区间对应一个叶子节点:内部节点对应部分区间,如对于一个内部节点[a, b]而言,其左子节点表示的区间为[a, (a+b)/2],其右子节点表示的区间为[1+(a+b)/2, b]: 对于区间长度为N的线段树,由于其单元节点都是[a, a]的叶子节点,所以其叶子节点数为N,并且整棵树为平衡二叉树,所以总节点数为2N-1,树的深度为log(N)+1: 插入操作:将一条线段[a, b]插入到

线段树经典操作模板(单点更新,替换;区间更新,替换;区间求和求最值)

对于线段树的讲解此篇不再赘述,下面列出线段树应用中最常用的几种操作的代码.(具体题目未贴出,仅供有一定基础者参考代码风格) 另外,注意多组输入要写scanf("%d%d",&n,&m)!=EOF,线段树的题肯定要用c语言的输入输出,要使用字符数组,不用字符串,输入字符的时候要加getchar()吞噬空行.. (1)单点增减,区间求和: #include<iostream> #include<stdio.h> #include<string&

Buy Tickets---poj2828(线段树)

题目链接:http://poj.org/problem?id=2828 题意就是有n个x y每次都是把y放到x位置,如果x位置有数,则把该位置之后的数往后放一位: [题解]: 线段树节点中保存这一段中的空位数,然后倒序对pos插入: 例如: 0 77 1 51 1 33 2 69 先取: 2 69      ——  ——  —69—   ——   (需要前面有3个空位才能插入) 然后取: 1 33       ——   —33—    —69—    ——   (需要前面有2个空位才能插入) 然

poj 2828 Buy Tickets (排队问题+线段树)

/* //不想写题解了,就直接把人家的粘过来了 线段树节点中保存这一段中的空位数,然后倒序对pos插入: 例如: 0 77 1 51 1 33 2 69 先取: 2 69 --  --  -69-   --   (需要前面有3个空位才能插入) 然后取: 1 33   --   -33-    -69-    --   (需要前面有2个空位才能插入) 然后取: 1 51   --   -33-    -69-    -51-   (需要前面有2个空位才能插入)  前面只有1个空位  故插入后面空格

POJ&mdash;&mdash;3264线段树

题目: 输入两个数(m,n),m表示牛的头数,n表示查询的个数.查询时输入两个数(x,y),表示查询范围的起始值和终止值,查询结果是,这个区间内牛重量的最大值减去牛重量的最小值,数量级为1000,000 设计每次查询的复杂度为logm. 例如, 输入: 6 3 1 7 3 4 2 5 1 5 4 6 2 2 输出: 6 3 0     分析:这道题是典型的空间换时间的题.一看到是区间的查找,我们应该想到线段树,这里有一篇我觉得写得挺好的介绍线段树的博客和大家分享一下:http://www.cnb