3173: [Tjoi2013]最长上升子序列

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1524  Solved: 797
[Submit][Status][Discuss]

Description

给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?

Input

第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)

Output

N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。

Sample Input

3
0 0 2

Sample Output

1
1
2

HINT

100%的数据 n<=100000

Source

 

[Submit][Status][Discuss]

分析

本来是想找Treap的练手题,考完NOIP放松一下心情的,结果看完题发现根本不用Treap……

首先,因为加入的元素是越来越大的,所以每次加入之后对于后面的元素的LIS的DP值(即以其结尾的最长上升子序列长度)不会改变,而前面的更不会改变。也就是说,最终序列的DP数组就是逐步加入的DP值了。所以只需要想方设法求出最终序列,再做一遍O(NlogN)的LIS问题即可。

求解最终的序列方法多种多样,可以用Treap暴力维护插入操作,也可以逆着推出最终的序列,我选择了后者。

对于第N个插入的元素,其插入的位置就是最终的位置。当它找到了最终位置之后,就把那个位置改为空。类似的,每个元素的最终位置,就是此时的第Xk个非空位置。这个操作用线段树维护即可轻松做到O(logN),当然也可以树状数组+二分做到O(log^2N),常数小也许跑得反而更快,(lll¬ω¬)。

代码

 #include <bits/stdc++.h>

 using namespace std;

 #define low lower_bound
#define upp upper_bound const int N = ;
const int inf = 0x3f3f3f3f; int n;
int pos[N];
int num[N];
int ans[N];
int stk[N]; struct node
{
int lt, rt, sum; node (void) :
lt (), rt (), sum () {};
}; node tree[N << ]; void build (int p, int l, int r)
{
node &t = tree[p]; t.lt = l;
t.rt = r; t.sum = r - l + ; if (l != r)
{
int mid = (l + r) >> ; build (p << , l, mid);
build (p << | , mid + , r);
}
} void change (int p, int pos, int val)
{
node &t = tree[p]; if (t.lt != t.rt)
{
int mid = (t.lt + t.rt) >> ; if (pos <= mid)
change (p << , pos, val);
else
change (p << | , pos, val); t.sum = tree[p << ].sum + tree[p << | ].sum;
}
else
t.sum = val;
} int query (int p, int val)
{
node &t = tree[p]; if (t.lt != t.rt)
{
int tmp = tree[p << ].sum; if (val <= tmp)
return query (p << , val);
else
return query (p << | , val - tmp);
}
else
return t.lt;
} signed main (void)
{
scanf ("%d", &n); for (int i = ; i <= n; ++i)
scanf ("%d", pos + i); build (, , n); for (int i = n; i >= ; --i)
{
int t = query (, pos[i] + );
num[t] = i, change (, t, );
} memset (stk, inf, sizeof(stk)); for (int i = ; i <= n; ++i)
{
*low (stk, stk + i, num[i]) = num[i];
ans[num[i]] = low (stk, stk + i, num[i]) - stk;
} for (int i = ; i <= n; ++i)
ans[i] = max (ans[i], ans[i - ]); for (int i = ; i <= n; ++i)
printf ("%d\n", ans[i] + );
}

BZOJ_3173.cpp

后记:

大概是刚考完NOIP,又要准备学考,大家的刷题兴致不高啊,居然被我轻松拿了Day榜,(*^_^*)/。

No. User Nick Name AC Submit Ratio
1 YOUSIKI ねえ、あなたは知っていますか、桜の行方の速度は秒速5センチメートル 5 6 83.333%

@Author: YouSiki

BZOJ 3173: [Tjoi2013]最长上升子序列的更多相关文章

  1. Bzoj 3173: [Tjoi2013]最长上升子序列 平衡树,Treap,二分,树的序遍历

    3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1183  Solved: 610[Submit][St ...

  2. BZOJ 3173: [Tjoi2013]最长上升子序列( BST + LIS )

    因为是从1~n插入的, 慢插入的对之前的没有影响, 所以我们可以用平衡树维护, 弄出最后的序列然后跑LIS就OK了 O(nlogn) --------------------------------- ...

  3. BZOJ 3173: [Tjoi2013]最长上升子序列 [splay DP]

    3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1613  Solved: 839[Submit][St ...

  4. bzoj 3173 [Tjoi2013]最长上升子序列 (treap模拟+lis)

    [Tjoi2013]最长上升子序列 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2213  Solved: 1119[Submit][Status] ...

  5. BZOJ 3173 [Tjoi2013] 最长上升子序列 解题报告

    这个题感觉比较简单,但却比较容易想残.. 我不会用树状数组求这个原排列,于是我只好用线段树...毕竟 Gromah 果弱马. 我们可以直接依次求出原排列的元素,每次找到最小并且最靠右的那个元素,假设这 ...

  6. BZOJ 3173: [Tjoi2013]最长上升子序列 (线段树+BIT)

    先用线段树预处理出每个数最终的位置.然后用BIT维护最长上升子序列就行了. 用线段树O(nlogn)O(nlogn)O(nlogn)预处理就直接倒着做,每次删去对应位置的数.具体看代码 CODE #i ...

  7. bzoj 3173: [Tjoi2013]最长上升子序列【dp+线段树】

    我也不知道为什么把题看成以插入点为结尾的最长生生子序列--还WA了好几次 先把这个序列最后的样子求出来,具体就是倒着做,用线段树维护点数,最开始所有点都是1,然后线段树上二分找到当前数的位置,把这个点 ...

  8. BZOJ 3173: [Tjoi2013]最长上升子序列 Splay

    一眼切~ 重点是按照 $1$~$n$ 的顺序插入每一个数,这样的话就简单了. #include <cstdio> #include <algorithm> #define N ...

  9. 3173: [Tjoi2013]最长上升子序列

    原题:http://www.lydsy.com/JudgeOnline/problem.php?id=3173 题解:促使我写这题的动力是,为什么百度遍地是Treap,黑人问号??? 这题可以用线段树 ...

随机推荐

  1. ubuntu系统下的防火墙使用

    apt-get install ufw      安装防火墙sudo ufw enable|disable|status         开启/关闭/查看防火墙状态sudo ufw allow 22/ ...

  2. eclipse服务器add and remove 工程时出现there are no resources that can be added or removed from the server

    网上的解决方法: 解决方法: 第1步.新建一个“Dynamic Web Project” 第2步.把新建项目里面的.project文件和.settings文件夹复制到导入的那个项目里面. 可是我发现: ...

  3. PL/SQL流程控制语句

    PL/SQL流程控制语句介绍PL/SQL的流程控制语句, 包括如下三类:控制语句: IF 语句循环语句: LOOP语句, EXIT语句顺序语句: GOTO语句, NULL语句①if语句 IF < ...

  4. bootstrap div 弹出与关闭

    html <div id="myModal" class="modal" tabindex="-1" role="dialo ...

  5. repeater 根据输入 返回汉字

    page repeater <asp:Repeater ID="r_scoreCount" runat="server"> <HeaderTe ...

  6. Html5 Egret游戏开发 成语大挑战(八)一般性二级页面处理

    在游戏中,我们一般会有各种各样的二级页面,比如游戏暂停界面或者游戏结束界面,这些界面组成了对玩家交互主要手段,在游戏开发中,对于这些界面的coding组织是非常有学问的,如果倒退到十年前,游戏开发的老 ...

  7. Cordova - 与iOS原生代码交互1(通过JS调用Swift方法)

    在前面的文章中介绍的了如何使用Cordova进行跨平台应用的开发,使用Cordova的话基本上就不需要在写系统原生代码了,只要通过编写html页面和js方法即可. 但在有些特殊情况下,还是是需要htm ...

  8. [py]简易pick lucky num程序

    程序功能: 1,用户输入数字,当用户输入指定数字时候,输出他输入的循环那次 2,第二次询问是否还要输 3,如果no 则 终止 4,如果yes则继续输入 判断输入是否大于首次输入的 如果大于则开始循环输 ...

  9. Android 的图片异步请求加三级缓存 ACE

    使用xUtils等框架是很方便,但今天要用代码实现bitmapUtils 的功能,很简单, 1 AsyncTask请求一张图片 ####AsyncTask #####AsyncTask是线程池+han ...

  10. 初学git:用git bash往github push代码

    对于我来说,最开始使用github主要是为了使用它的pages功能展示demo.其实这些都是用Github for Windows push上去的,图形化界面的客户端使用确实简单,但是逼格不够,好吧其 ...