题目





像素有点低啊~

算了凑合一下就好啦~

题目大意

给你一个首尾相接的数列,每次对一个区间进行操作:

顺时针操作,如果当前值比vvv大,就交换。输出最后的vvv。


比赛思路

首先这题的时限这么仁慈,一定有天大玄机。

并且一看这题,就感觉像是一个数据结构。

首先在想链表,但显然这题链表不可做。

然后一直在想带修主席树。

没想出来……

最后弃疗,直接打了个暴力。

WTF?15分?说好的25分呢?

然而实际上这题很没良心地捆绑数据,将10分和另外15分绑在一起了。

出题人,你怎么能这样子啊?你忍心吗?


正解

这题WMY大佬说可以用带修主席树做。

刚了一个下午,最终,他弃疗了……

原因是标记不好下传。

实际上正解是分块。

首先看到时间复杂度,我们就应该想到这题可以随意给你搞事情。

然而我就是没有想到分块!!!

首先,对于一个区间,如果有一个操作经过了这个区间,设区间中的最大值为mxmxmx。若mx>vmx>vmx>v,则交换,否则继续。

这个结论是很显然的,依靠这个结论可以再拿15分。

我们可以将其分块,每个块的大小为KKK。对于每个块,我们维护一个大根堆,存下这个块里面的所有值。

如果处理整块,就直接和最大值比较,然后像之前一样操作。并且,在这个块上打一个标记。

如果处理散块,就要将这个散块还原,然后暴力搞一遍。

如何还原呢?

首先,对于每个块,我们将标记存在一个小根堆里面。

在还原的时候,我们从左到右扫,对于每个值,用小根堆的堆顶操作。如果ai>va_i>vai​>v,就交换(也就是将vvv弹出,将aia_iai​加入,并且改变aia_iai​的值)

最后将标记清空。

这就还原了整个块了,然后暴力搞一遍,重构大根堆。

那么问题来了,为什么每次用小根堆的堆顶操作?

可以感性地理解一下:

对于第一个,这些标记的操作都会对它有操作。如果当前的这个值大于vvv,那么就要被交换。而交换那么多遍,最后真正能对它做出影响的是最小的vvv,其它的东西都会传到后面去。

然后对于后面的,也是一样的道理。

和氧化还原反应好像啊!——ZJQ

所以整块的时间复杂度是O(qnKlg⁡K)O(q\frac{n}{K}\lg K)O(qKn​lgK),散块的时间复杂度是O(qKlg⁡q)O(qK\lg q)O(qKlgq)

然后平衡规划一下,得出KKK大概为n\sqrt nn​。

然而分块的常数是有差异的,所以KKK的取值据实际而定。

我取了800800800。当我取600600600时,程序就崩了,或许是堆太多了吧。(我用了STL的堆)


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 400000
#define K 800
int n,q;
int a[N];
int m;
#define bel(x) ((x)/K)
#define nxt(x) (((x)+1==m)?(0):((x)+1))
priority_queue<int> h[N/K];
priority_queue<int,vector<int>,greater<int> > bz[N/K];
inline void pushdown(int b,int l,int r,int &v){//处理散块
//还原
if (!bz[b].empty()){
for (int i=b*K;i<b*K+K && i<n;++i){
int t=bz[b].top();
if (a[i]>t){
bz[b].pop();
bz[b].push(a[i]);
a[i]=t;
}
}
while (!bz[b].empty())
bz[b].pop();
}
//暴力处理
for (int i=l;i<=r;++i)
if (a[i]>v)
swap(a[i],v);
//重构
while (!h[b].empty())
h[b].pop();
for (int i=b*K;i<b*K+K && i<n;++i)
h[b].push(a[i]);
}
inline void getinto(int b,int &v){//表示处理整块,v进入b中,再出来
int t=h[b].top();
if (t>v){
h[b].pop();
h[b].push(v);
bz[b].push(v);
v=t;
}
}
int main(){
scanf("%d%d",&n,&q);
for (int i=0;i<n;++i)
scanf("%d",&a[i]);
m=(n-1)/K+1;
for (int i=0;i<m;++i)
for (int j=0;j<K && i*K+j<n;++j)
h[i].push(a[i*K+j]);
while (q--){
int l,r,v;
scanf("%d%d%d",&l,&r,&v);
l--,r--;
int bl=bel(l),br=bel(r);
if (bl==br){
if (l<=r)
pushdown(bl,l,r,v);
else{
pushdown(bl,l,min(bl*K+K-1,n-1),v);
for (int i=nxt(bl);i!=br;i=nxt(i))
getinto(i,v);
pushdown(br,br*K,r,v);
}
}
else{
if (l==bl*K)
getinto(bl,v);
else
pushdown(bl,l,min(bl*K+K-1,n-1),v);
for (int i=nxt(bl);i!=br;i=nxt(i))
getinto(i,v);
if (r==min(br*K+K-1,n-1))
getinto(br,v);
else
pushdown(br,br*K,r,v);
}
printf("%d\n",v);
}
return 0;
}

我才发现原来要打个cpp才能有颜色,我之前打的都是C++,天哪,博客更新之后就是不一样!


总结

看见时限大的题,往分块方面想一想,或许就能很好解决了。

分块的优点,在于它只需要对整块和散块分块处理,也就是说,不像线段树那样下传时这么复杂。

还有,这题有没有其他的方法。比如,分块套分块(手动滑稽)

JZOJ5967 常数国的更多相关文章

  1. Before NOIP 2018

    目录 总结 刷题 2018 - 9 - 24 2018 - 9 - 25 2018 - 9 - 26 2018 - 9 - 27 2018 - 9 - 28 2018 - 9 - 29 2018 - ...

  2. [jzoj NOIP2018模拟10.23]

    丢分主要是下面几个方面: 1.T2代码交错了,有个特判没写丢了10分 2.T1线段树加等差数列写错了(其实二维差分就可以,但我当时不会) 3.T3思考再三还是为了10分写上了主席树,还是写错了 总体评 ...

  3. 解析大型.NET ERP系统 多国语言实现

    实现多国语言有许多种实现方案,无外乎是一种字符串替换技术,将界面控件的文本标签替换成相应语言的文字..NET Windows Forms实现多国语言的方法有以下几种: 1 .NET的方案,使用资源文件 ...

  4. [LeetCode] Insert Delete GetRandom O(1) - Duplicates allowed 常数时间内插入删除和获得随机数 - 允许重复

    Design a data structure that supports all following operations in average O(1) time. Note: Duplicate ...

  5. [LeetCode] Insert Delete GetRandom O(1) 常数时间内插入删除和获得随机数

    Design a data structure that supports all following operations in average O(1) time. insert(val): In ...

  6. Flex 1046: 找不到类型,或者它不是编译时常数;1180: 调用的方法 CompPropInfo 可能未定义

    导入项目之后一直报这个错误, 1046: 找不到类型,或者它不是编译时常数: 1180: 调用的方法 CompPropInfo 可能未定义 想这应该是没有把当前这个类编译进项目当中,找了半天也没有找到 ...

  7. 高质量,高效率的多国语言软件开发(Web/PC/Mobile),使用接口约束/调用不同语言资源

    偶然间翻出了几年前写的一个小程序,把当时的资料整理整理分享一下. 当时为了给自己的软件实现多国语言功能,而开发的辅助工具:SE String Resource. 这是当时基于自己另一款 IDE 软件抽 ...

  8. ARM的常数表达式

    ARM的常数表达式   如果说Intel指令中的立即数,相信大家都很熟悉.类似的,Arm指令中的“立即数”就是常数表达式.之所以称为常数表达式,而不称为立即数是有原因的. Intel指令属于CISC指 ...

  9. Atitti 存储引擎支持的国内点与特性attilax总结

    Atitti 存储引擎支持的国内点与特性attilax总结 存储引擎处理的事情: · 并发性:某些应用程序比其他应用程序具有很多的颗粒级锁定要求(如行级锁定). · 事务支持:并非所有的应用程序都需要 ...

随机推荐

  1. odoo 分组视图下显示同一批次记录的总数

    修改前: 修改后: xml文件: <?xml version="1.0" encoding="utf-8"?> <!-- vim:fdn=3: ...

  2. Windows 关闭win32 控制台

    {     fclose(pf); BOOL ret = FreeConsole(); }

  3. C++——运算符重载

    运算符重载编程基础 例如: //全局函数 完成 +操作符 重载  Complex operator+(Complex &c1, Complex &c2) //类成员函数 完成 -操作符 ...

  4. 资源-Android:Android

    ylbtech-资源-Android:Android 1.返回顶部 1. https://developer.android.google.cn/studio 2. 2.返回顶部 1. 1.1 1.2 ...

  5. UVA-699-The Falling Leaves-二叉树+递归

    Each year, fall in the North Central region is accompanied by the brilliant colors of the leaves on ...

  6. PAT甲级——A1118 Birds in Forest【25】

    Some scientists took pictures of thousands of birds in a forest. Assume that all the birds appear in ...

  7. Java代码启动/关闭进程

    ProcessBuilder builder = new ProcessBuilder(命令,参数,参数...); Process process = builder.start(); br = ne ...

  8. 第十篇:javaScript中的JSON总结

    参考网站:json中国,MDN json 一.必知基础    JSON 是JavaScript对象文字符号的一个子集,它可以自如的在JavaScript中使用.看下这个对象: var myJSONOb ...

  9. 第二天:数值与字符串、列表list

    数值 1. 声明变量 age = 20 f = 3.14 #浮点型 f = 0.3 f = .3 2.表达式 主要是做一些简单的加减乘除运算,直接出结果 1.1 + 2.2 2.2 + 3.0 3.1 ...

  10. scrapy爬虫框架爬取招聘网站

    目录结构 BossFace.py文件中代码: # -*- coding: utf-8 -*-import scrapyfrom ..items import BossfaceItemimport js ...