POJ2828---线段树与逆序数&&DUTOJ1210---逆序对构造排列
来看这样一道问题:http://acm.dlut.edu.cn/problem.php?id=1210
题目大意:对于一个1-n的排列,a1,a2,a3,a4...an我们把满足i < j,ai > aj这样的数对(ai,aj)成为一个逆序对,另有一个数组b【i】记录aj = i这样的逆序对的个数,例如排列:
3 1 5 2 4,对应的逆序数组b[1] = 1,b2[2] = 2,b[3] = 0,b[4] = 1,b[5] = 0;换句话说,b【i】代表了i之前有多少比它大的数;
问:给出一个b数组,构造出一个符合情况的排列a,1 <=n<=100000;
容易看出,最后的排列一定是唯一的,先来想一想最暴力的解法,其实如果不是因为n的大小是十万级别的话,很容易想到暴力插入的方式,那就是先让大的占位置;
(1)b【5】= 0:先把5放在排列开头:5;
(2)b【4】= 1:4前面比4大的有一个:5,4;
(3)b【3】= 0,3前面比3大的有0,显然:3,5,4;
(4)b【2】= 2:比2大的有2个:3,5,2,4;
(5)b【1】= 1:比1大的有3,1,5,2,4;这就是最终的结果;
按照这种方式插入很定可以构造出最终结果,显然插入一个数时要移动数据元素,最终的复杂度是o(n^2)的,肯定会超时;
同时我们来看POJ2828:
Description
n个人排队,输入第一行为n的值,接下来输入n行,每行一个x值,一个val值,x代表第i个人插入的位置前面有多少个人,i从1到n;
Sample Input
4
0 77
1 51
1 33
2 69
4
0 20523
1 19243
1 3890
0 31492
Sample Output
77 33 69 51
31492 20523 3890 19243
这两个题几乎就是一个题嘛,对于这种插队问题,需要离线来做;
因为先插进来的人会影响到后面的人,但是对于最后一个插队的人来说如果他前面有x个人,最终他肯定就在x + 1的位置上。所以需要离线处理并且逆序进行插入;
我们用一个sum数组表示位置i有没有空位即能不能插进来一个人,sum【i】 = 1代表这个位置上能插进来一个人,sum = 0表示不能插入;
以poj2828的第一组样例为例:
注意sum下标从0开始
sum:1 1 1 1 1表示5个位置上都可以插入,如果我们把(2,69)插入:
sum:1 1 0 1 1那么肯定第三个位置上的数字是69;再插入(1,33),
注意到33插在69的前面,实际上当33插入的时候,69还没插入,所以69和33根本互不影响,所以33肯定也是插在第1个位置
sum:1 0 0 1 1,我们再插入(1,51),这里就怪了,sum【1】貌似已经被33占据了,那么怎么处理51呢?实际上我们知道,在插入51时,33和69都没进来呢,所以可以暂时认为sum【1】和sum【2】都不存在,
显然51应该插入在第1个1上面,即sum【3】:
sum:1 (0 0) 0 1;注意这里括号括起来的是咱们假想的,真正插入51的时候,33和69还没插进呢,所以51确实插入了第“1”个位置,因为在33,69没插进来时,前面只有一个第0个位置有空。
所以这里插入的原则就很清楚了,对于一个(x,value),应该插入到第x个1的位置,怎么统计位置i前面有几个1呢??那不正是统计sum的前缀和嘛?怎么统计区间和?线段树嘛! 插入(x,value)时,线段树把一个区间分为一个左子区间和一个右左区间,如果左区间还有x个空间可以插入,就应该到左子区间去更新;否则应该到右子区间去查询,但是此时,查询的位置应该减去
sum【rson】用以表示相对的位置,因为sum里面保存的是区间之内有几个位置可以插入,所以进入右子区间时,应该减掉在左子区间里的那些“1”的个数,所以这里用的是相对位置;
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define INF 100000000
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define lc rt<<1
#define rc rt<<1|1
using namespace std;
const int maxn = 2e5 + ;
typedef long long ll; int pos[maxn], val[maxn];
int sum[maxn << ];
int ans[maxn];
int n; void pushup(int rt)
{
sum[rt] = sum[lc] + sum[rc];
}
void build(int rt, int l, int r)
{
if(l == r) {
sum[rt] = ;
return;
}
int m = (l + r) >> ;
build(lc, l, m);
build(rc, m + , r);
pushup(rt);
}
void update(int p, int add, int l , int r , int rt ) {
if(l == r) {
sum[rt] = ;
ans[l] = add;
return ;
}
int m = (l + r) >> ;
if(p <= sum[rt << ])update(p, add, l,m,lc);
else update(p - sum[rt << ], add, m+,r,rc);
pushup(rt);
}
int main()
{
for(;~scanf("%d", &n);)
{
for(int i = ; i <= n; ++i)
scanf("%d%d", pos + i, val + i);
build(, , n);
for(int i = n; i >= ; --i)
{
int p = pos[i]+;
int v = val[i];
update(p, v, , n, );
}
for(int i = ; i <= n; ++i)
printf("%d%c", ans[i], (i ^ n ? ' ' : '\n'));
memset(ans, , sizeof(ans));
}
}
POJ2828---线段树与逆序数&&DUTOJ1210---逆序对构造排列的更多相关文章
- POJ.2299 Ultra-QuickSort (线段树 单点更新 区间求和 逆序对 离散化)
POJ.2299 Ultra-QuickSort (线段树 单点更新 区间求和 逆序对 离散化) 题意分析 前置技能 线段树求逆序对 离散化 线段树求逆序对已经说过了,具体方法请看这里 离散化 有些数 ...
- HDU.1394 Minimum Inversion Number (线段树 单点更新 区间求和 逆序对)
HDU.1394 Minimum Inversion Number (线段树 单点更新 区间求和 逆序对) 题意分析 给出n个数的序列,a1,a2,a3--an,ai∈[0,n-1],求环序列中逆序对 ...
- hdu 1394 Minimum Inversion Number(线段树之 单点更新求逆序数)
Minimum Inversion Number T ...
- csu 1555(线段树经典插队模型-根据逆序数还原序列)
1555: Inversion Sequence Time Limit: 2 Sec Memory Limit: 256 MBSubmit: 469 Solved: 167[Submit][Sta ...
- codeforces_459D_(线段树,离散化,求逆序数)
链接:http://codeforces.com/problemset/problem/459/D D. Pashmak and Parmida's problem time limit per te ...
- POJ2828线段树单点更新——逆序更新
Description 输入n个有序对< pi, vi >,pi表示在第pi个位置后面插入一个值为vi的人,并且pi是不降的.输出最终得到的v的序列 Input 多组用例,每组用例第一行为 ...
- 51nod 1019 逆序数(逆序数+离散化)
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 如2 4 3 1中,2 1,4 3,4 1,3 1是 ...
- 归并求逆序数(逆序对数) && 线段树求逆序数
Brainman Time Limit: 1000 MS Memory Limit: 30000 KB 64-bit integer IO format: %I64d , %I64u Java c ...
- poj 2828 Buy Tickets【线段树单点更新】【逆序输入】
Buy Tickets Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 16273 Accepted: 8098 Desc ...
随机推荐
- shell中的替换
shell中如果存在一些特殊的字符,就需要进行替换,可进行命令替换.变量替换.转义替换 1.转义字符的替换 shell中包含以下的转移字符 \a 响铃警报\\ 反斜杠 \b 退格(删除键) ...
- Horizontal,vertical,Input_Mouse,Input_Key
鼠标获取 using UnityEngine; using System.Collections; public class Input_Mouse : MonoBehaviour { void Up ...
- 【C#正则基础】正则表达式
1. 代表任意多个字符:(.*?)2. 代表网页里的<body>*</body>任意的标签内容,替换以后网页源码就只剩纯文本:<[^>]*>3. 代表网页中的 ...
- 读《MacTalk·人生元编程》及Mac经常使用软件
引子 池建强的Blog:http://www.cnblogs.com/chijianqiang/ 用了1年多的黑苹果,是用Windows的思维用UI.用Linux的思维用Shell,折腾的是联想E49 ...
- c# 操作PPT
前段时间要做一个把指定图片放到新建的ppt的东西,在网上找了点资料看了一下,发现用C#做好像是最简单的一个,一下是在网上找的一段代码,直接贴进去就能够执行,可是在执行之前一定要加入dll支持: 项目 ...
- asp.net验证控件注意事项
1.如果触发某个控件事件是只对指定验证控件进行验证,可以将验证控件和被触发控件放到到一个ValidationGroup中.比如点提交按钮的时候,验证文本框,可以将提交按钮和验证控件放到一个Valida ...
- 使用Teleport Pro离线下载网页所有内容
在学习生活中,碰到网页中内容太多,如何讲其保存到本地,已方便随时查看呢? 使用Teleport Pro就可以解决问题: 首先下载Teleport Pro V1.54 汉化绿色版的,解压完之后 ...
- Discuz!NT 3.5.2正式版与Asp.net网站会员信息整合
Discuz!NT 提供了很多对外的接口利于与别的网站进行整合,经本人亲测,觉得开放的接口还是挺到位的.开发.测试一次通过,只不过api文档寻找无门,只能自己琢磨,费了不少周折,不过,功夫不负有心人, ...
- 单源最短路径 hdu 2066
#include<string.h> //和prim类似#include<stdio.h> //prim所考虑的是节点与当前所建成的树的距离最小using namespace ...
- C/C++中虚函数的调用
代码: #include <iostream> using namespace std; class A{ public: virtual void print(){ cout<&l ...