Time Limit: 20 Sec  Memory Limit: 128 MB

Submit: 371  Solved: 187

[Submit][Status][Discuss]

Description

佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。玩具上有一个数列,数列中某些项的值

可能会变化,但同一个时刻最多只有一个值发生变化。现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你
,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可
。注意:每种变化最多只有一个值发生变化。在样例输入1中,所有的变化是:
1 2 3
2 2 3
1 3 3
1 1 31 2 4
选择子序列为原序列,即在任意一种变化中均为不降子序列在样例输入2中,所有的变化是:3 3 33 2 3选择子序列
为第一个元素和第三个元素,或者第二个元素和第三个元素,均可满足要求

Input

输入的第一行有两个正整数n, m,分别表示序列的长度和变化的个数。接下来一行有n个数,表示这个数列原始的

状态。接下来m行,每行有2个数x, y,表示数列的第x项可以变化成y这个值。1 <= x <= n。所有数字均为正整数
,且小于等于100,000

Output

输出一个整数,表示对应的答案

Sample Input

3 4

1 2 3

1 2

2 3

2 1

3 4

Sample Output

3

【题解】

题的意思是说进行一次变化操作之后,变成新的序列,然后序列又变回原状,然后再进行下一个变换,变成新状态->又变回原状。。

然后在这几次变化之后形成的所有序列。找一个下标a1,a2..at,在这所有形成的序列中都都要满足a[a1]<=a[a2]<=...<=a[at].

求t的最大值。

设下标为i的数字最大会变成r[i],最小会变成l[i].然后原数字是v[i]

则第j个元素能接在第i个元素后面加长以第i个元素为结尾的最长上升序列的长度的条件是r[i] <= a[j]且a[i] <= l[j].前者是第i个元素发生变化,后者是第j个元素发生变化所要满足的情况。

还是提醒一句。进行一次操作过后。马上序列又变回原状。而且每次操作只会改变一个对应下标的数字。

则f[j] = max(f[i])+1;(i∈1..j-1;a[i] <= l[j]且r[i] <= a[j])

但是n=10W.

这种做法是n^2的。。

于是做一下改进。

我们在转移的时候实际上就是在找某些范围里面的点。

我们设点的坐标为(a[p],r[q]);(抽象)

那我们对第i个数字进行DP的时候

实际上就是要在某种数据结构中找坐标范围为(0..l[i],0..a[i])的点里面f值最大的。

转移完之后就获得了f[i]的值。

然后再把第i个点的f[i]加到这种数据结构里面就好了。

这种问题可以用kdtree来实现。

n太巨大。需要不时重建kdtree。不然插入操作会让kdtree退化。

经过试验每6000次重建一次效果最好。5000也能通过。

4000、10000这些周期则会T

具体看代码

【代码】

#include <cstdio>
#include <algorithm> using namespace std; const int MAXN = 109000; int n, m,root,ans = 0,now; struct point
{
int l, r,v;
}; struct node
{
int ma_x[2], mi_n[2], l, r, dot,f, max,d[2];
}; point shuju[MAXN];
node t[MAXN],op;
int totn = 0,mi_n[2],ma_x[2]; void input_data()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
scanf("%d", &shuju[i].v);
shuju[i].l = shuju[i].r = shuju[i].v;
}
for (int i = 1; i <= m; i++)
{
int index, num;
scanf("%d%d", &index, &num);
shuju[index].l = min(shuju[index].l, num);
shuju[index].r = max(shuju[index].r, num);
}
} void up_data(int rt)
{
int l = t[rt].l, r = t[rt].r;
for (int i = 0; i <= 1; i++)
{
if (l)
{
t[rt].ma_x[i] = max(t[rt].ma_x[i], t[l].ma_x[i]);
t[rt].mi_n[i] = min(t[rt].mi_n[i], t[l].mi_n[i]);
if (t[l].max > t[rt].max)
{
t[rt].max = t[l].max;
//t[rt].dot = t[l].dot;
}
}
if (r)
{
t[rt].ma_x[i] = max(t[rt].ma_x[i], t[r].ma_x[i]);
t[rt].mi_n[i] = min(t[rt].mi_n[i], t[r].mi_n[i]);
if (t[r].max > t[rt].max)
{
t[rt].max = t[r].max;
//t[rt].dot = t[r].dot;
}
}
}
} void insert(int &rt, int fx)//插入节点
{
if (!rt)
{
rt = ++totn;
t[rt] = op;
t[rt].max = t[rt].f;
t[rt].l = t[rt].r = 0;
//t[rt].dot = rt;
for (int i = 0; i <= 1; i++)
t[rt].ma_x[i] = t[rt].mi_n[i] = t[rt].d[i];
return;
}
else
{
if (op.d[fx] < t[rt].d[fx])
insert(t[rt].l, 1 - fx);
else
insert(t[rt].r, 1 - fx);
}
up_data(rt);
} int query(int rt)
{
if (!rt)
return 0;
if (mi_n[0] <= t[rt].mi_n[0] && t[rt].ma_x[0] <= ma_x[0]
&& mi_n[1] <= t[rt].mi_n[1] && t[rt].ma_x[1] <= ma_x[1])
return t[rt].max; //整棵子树里面的点都在所求范围内
if (t[rt].ma_x[0] < mi_n[0] || t[rt].mi_n[0] > ma_x[0] || t[rt].ma_x[1] < mi_n[1]
|| t[rt].mi_n[1] > ma_x[1])//都不在范围内
return 0;
int big = 0;
if (mi_n[0] <= t[rt].d[0] && t[rt].d[0] <= ma_x[0] &&
mi_n[1] <= t[rt].d[1] && t[rt].d[1] <= ma_x[1])
big = max(big, t[rt].f);//当前这个节点在范围内。
int l = t[rt].l, r = t[rt].r;
if (l)
big = max(big, query(l));
if (r)
big = max(big, query(r));
return big;
} bool cmp(node a, node b)
{
return a.d[now] < b.d[now];
} int rebuild(int begin, int end, int fx)
{
int m = (begin + end) >> 1;
now = fx;
nth_element(t + begin, t + m, t + end + 1, cmp);
for (int i = 0; i <= 1; i++)
t[m].ma_x[i] = t[m].mi_n[i] = t[m].d[i];
t[m].max = t[m].f;
if (begin < m)
t[m].l = rebuild(begin, m - 1, 1 - fx);
else
t[m].l = 0;//不能省,要重建的
if (m < end)
t[m].r = rebuild(m + 1, end, 1 - fx);
else
t[m].r = 0;
up_data(m);
return m;
} void get_ans()
{
//j < i r[j] <= v[i]
//j < i v[j] <= l[i]
op.d[0] = shuju[1].r;
op.d[1] = shuju[1].v;
op.f = 1;
insert(root,0);
ans = 1;
for (int i = 2;i <= n;i++)
{
if ((i % 6000) == 0)
{
root = rebuild(1, totn,0);
}
mi_n[0] = 0; ma_x[0] = shuju[i].v;
mi_n[1] = 0; ma_x[1] = shuju[i].l;
int temp = query(root);
op.d[0] = shuju[i].r;
op.d[1] = shuju[i].v;
op.f = 1;
if (temp)
{
if (temp + 1 > ans)
ans = temp + 1;
op.f = temp + 1;
}
insert(root, 0);
}
} void output_ans()
{
printf("%d\n", ans);
} int main()
{
//freopen("F:\\rush.txt", "r", stdin);
input_data();
get_ans();
output_ans();
return 0;
}

【50.40%】【BZOJ 4553】[Tjoi2016&Heoi2016]序列的更多相关文章

  1. BZOJ 4553 Tjoi2016&Heoi2016 序列

    Tjoi2016&Heoi2016序列 Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值 可能会变化,但同一个时刻最 ...

  2. BZOJ 4553 [Tjoi2016&Heoi2016]序列 ——CDQ分治 树状数组

    考虑答案的构成,发现是一个有限制条件的偏序问题. 然后三个维度的DP,可以排序.CDQ.树状数组各解决一维. #include <map> #include <cmath> # ...

  3. 4553: [Tjoi2016&Heoi2016]序列

    4553: [Tjoi2016&Heoi2016]序列 链接 分析: 注意所有m此操作中,只会发生一个,于是考虑dp.dp[i]=dp[j]+1,j<i,a[j]<=L[i],R[ ...

  4. [BZOJ4553][TJOI2016&&HEOI2016]序列(CDQ分治)

    4553: [Tjoi2016&Heoi2016]序列 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1202  Solved: 554[Su ...

  5. [BZOJ4553][Tjoi2016&Heoi2016]序列 cdp分治+dp

    4553: [Tjoi2016&Heoi2016]序列 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 260  Solved: 133[Sub ...

  6. 【BZOJ4553】[Tjoi2016&Heoi2016]序列 cdq分治+树状数组

    [BZOJ4553][Tjoi2016&Heoi2016]序列 Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值可能 ...

  7. bzoj4553 [Tjoi2016&Heoi2016]序列 树状数组(区间最大值)+cqd

    [Tjoi2016&Heoi2016]序列 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1006  Solved: 464[Submit][ ...

  8. BZOJ 4552: [Tjoi2016&Heoi2016]排序

    4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 579  Solved: 322[Sub ...

  9. BZOJ 4554: [Tjoi2016&Heoi2016]游戏 二分图匹配

    4554: [Tjoi2016&Heoi2016]游戏 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4554 Descripti ...

  10. bzoj 4555 [Tjoi2016&Heoi2016]求和 NTT 第二类斯特林数 等比数列求和优化

    [Tjoi2016&Heoi2016]求和 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 679  Solved: 534[Submit][S ...

随机推荐

  1. Directx11 教程(1) 基本的windows应用程序框架(1)

    原文:Directx11 教程(1) 基本的windows应用程序框架(1)        在vs2010中,建立一个新的win32工程,名字是: myTutorialD3D11, 注意:同时勾选Cr ...

  2. WPF/Silverlight深度解决方案:(九)HLSL自定义渲染特效之完美攻略(下)

    原文:WPF/Silverlight深度解决方案:(九)HLSL自定义渲染特效之完美攻略(下) 本想只用两节来完成关于HLSL自定义渲染相关知识的讲解,鉴于最近非常的多的朋友对此相当感兴趣,想知道最多 ...

  3. PLAY2.6-SCALA(九) WebSockets

    WebSockets是一种支持全双工通信的套接字.现代的html5通过js api使得浏览器天生支持webSocket.但是Websockets在移动端以及服务器之间的通信也非常有用,在这些情况下可以 ...

  4. firefox扩展开发(二):用XUL创建窗口控件

    firefox扩展开发(二):用XUL创建窗口控件 2008-06-11 16:57 1.创建一个简单的窗口 <?xml version="1.0"?> <?xm ...

  5. spring boot 2.X上传文件限制大小

    Spring Boot 1.3.x multipart.maxFileSize multipart.maxRequestSize Spring Boot 1.4.x and 1.5.x spring. ...

  6. oracle交互命令

    (1)说明:可以替代变量,而该变量在执行时,需要用户输入. sql>select * from emp where job=’&job’; (2)edit  说明:该命令可以编辑指定的s ...

  7. BZOJ 4551树题解

    好吧,洛谷的数据比较水暴力就可以过....(而且跑到飞快) 不过(BZ水不过去)还是讲讲正规的做法. 其实一眼可以看出可以树剖,但是,码起来有点麻烦. 其实有一种更简单的离线做法. 我们很容易联想到并 ...

  8. Effective C++: 02构造、析构、赋值运算

    05:了解C++默默编写并调用哪些函数 1:一个空类,如果你自己没声明,编译器就会为它声明(编译器版本的)一个copy构造函数.一个copy assignment操作符和一个析构函数.此外如果你没有声 ...

  9. 记忆化搜索(DFS)--How many ways

    How many ways 这是一个简单的生存游戏,你控制一个机器人从一个棋盘的起始点(1,1)走到棋盘的终点(n,m).游戏的规则描述如下:1.机器人一开始在棋盘的起始点并有起始点所标有的能量.2. ...

  10. Flask学习之一 hello world

    本人电脑环境: 系统:linux