题意

给一个长度为 \(n\) 的序列, \(q\) 次询问,次给一个 \(k_i\) ,问最少将序列划分成多少次,满足每一段的极差不超过\(w−k_i\).

\(1 \leq n, q \leq 10^5, 1 \leq w \leq 10^9,1 \leq k_i \leq w,0 \leq x_i \leq 10^9\)

分析

  • 每次直接贪心是正确的,可以考虑从第一段的影响证明,一定是尽量减少第二段的负担。

  • 记 \(k=w-k\) ,把询问按照 \(k\) 排序,那么段数显然单调不升。

  • 记 \({nxt}_i\) 表示 \(i\) 位置在当前询问的 \(k\) 下合法的最远位置 \(+1\) ,连边 \(i \rightarrow {nxt}_i\)。

  • 考虑在 \(k\) 变大的时候,我们修改一些位置的 \(nxt\),并使用 \(lct\) 加删边。如果 \({nxt}_i-i \geq \sqrt n\) 则不再连边。

    查询时如果走到了一棵树的树根便进行二分找到树根的 \(nxt\) ,因为二分时一定至少跳了 \(\sqrt n\) 步,所以这样的操作不会超过 \(\sqrt n\) 个。

  • 总时间复杂度为 \(O(n\sqrt nlogn)\)。

  • 感觉这种按数据根号分类的题都是平衡了两种暴力之间的复杂度

代码

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
inline int gi(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
return x*f;
}
const int N=1e5 + 7;
int n,w,Q,sz;
int x[N],nxt[N],mi[N][20],mx[N][20],Log[N],ans[N];
struct qs{
int k,id;
bool operator <(const qs &rhs)const{
return k<rhs.k;
}
}q[N];
int fa[N],tr[N][2],son[N],rev[N];
#define pa fa[o]
#define Ls tr[o][0]
#define Rs tr[o][1]
bool isrt(int o){return tr[pa][0]^o&&tr[pa][1]^o;}
int side(int o){return tr[pa][1]==o;}
void pushup(int o){ son[o]=son[Ls]+son[Rs]+1; }
void rotate(int o){
int f=pa,y=fa[pa],x=side(o),s=tr[o][x^1];
if(!isrt(f)) tr[y][side(f)]=o;fa[o]=y;
tr[f][x]=s,fa[s]=f;
tr[o][x^1]=f,fa[f]=o;
pushup(f),pushup(o);
}
void splay(int o){
for(;!isrt(o);rotate(o))
if(!isrt(pa)) rotate(side(o)==side(pa)?pa:o);
}
void access(int o){
for(int y=0;o;y=o,o=pa) splay(o),Rs=y,pushup(o);
}
void link(int a,int b){
access(a),splay(a);
fa[a]=b;
}
void cut(int a,int b){
access(a),splay(a);
int x=tr[a][0];
fa[x]=tr[a][0]=0;
pushup(a);
}
int dep(int o){
access(o);splay(o);
return son[o];
}
int findr(int o){
access(o);splay(o);
while(Ls) o=Ls;
return o;
}
vector<int>G[N];
int qmx(int l,int r){
int k=Log[r-l+1];
return max(mx[l][k],mx[r-(1<<k)+1][k]);
}
int qmi(int l,int r){
int k=Log[r-l+1];
return min(mi[l][k],mi[r-(1<<k)+1][k]);
}
int main(){
n=gi(),w=gi(),Q=gi();sz=sqrt(n); rep(i,1,n) x[i]=mi[i][0]=mx[i][0]=gi();
x[n+1]=mi[n+1][0]=mx[n+1][0]=2e9+1; Log[1]=0; rep(i,2,n+1) Log[i]=Log[i>>1]+1;
for(int k=1;1<<k<=n+1;++k)
for(int i=1;i+(1<<k)-1<=n+1;++i){
mi[i][k]=min(mi[i][k-1],mi[i+(1<<k-1)][k-1]);
mx[i][k]=max(mx[i][k-1],mx[i+(1<<k-1)][k-1]);
} rep(i,1,Q){
q[i].id=i,q[i].k=w-gi();
} sort(q+1,q+1+Q);
rep(i,1,n+1) son[i]=1;
rep(i,1,n) nxt[i]=i,G[1].pb(i); rep(i,1,Q){
for(auto p:G[i]){
if(i!=1) cut(p,nxt[p]);
int j=nxt[p]+1;
for(;j<=min(p+sz,n+1);++j) if(qmx(p,j)-qmi(p,j)>q[i].k) break;
if(j==p+sz+1) continue; nxt[p]=j,link(p,j);
int x=lower_bound(q+1,q+1+Q,(qs){qmx(p,nxt[p])-qmi(p,nxt[p]),0})-q;
if(x!=Q+1) G[x].pb(p);
} int &res=ans[q[i].id];
for(int j=1;j<=n+1;){
res+=dep(j),j=findr(j);
if(j==n+1) break; int l=j+1,r=n+1;
while(l<r){
int mid=l+r>>1;
if(qmx(j,mid)-qmi(j,mid)>q[i].k) r=mid;
else l=mid+1;
}
j=l;
}
}
rep(i,1,Q) printf("%d\n",ans[i]-2);
return 0;
}

[CF1039E]Summer Oenothera Exhibition[根号分治+lct]的更多相关文章

  1. CF1039E Summer Oenothera Exhibition 根号分治,LCT,ST表

    CF1039E Summer Oenothera Exhibition LG传送门 根号分治好题. 可以先看我的根号分治总结. 题意就是给出长度为\(n\)的区间和\(q\)组询问以及一个\(w\), ...

  2. CF1039E Summer Oenothera Exhibition 贪心、根号分治、倍增、ST表

    传送门 感谢这一篇博客的指导(Orzwxh) $PS$:默认数组下标为$1$到$N$ 首先很明显的贪心:每一次都选择尽可能长的区间 不妨设$d_i$表示在取当前$K$的情况下,左端点为$i$的所有满足 ...

  3. Codeforces 1039D You Are Given a Tree [根号分治,整体二分,贪心]

    洛谷 Codeforces 根号分治真是妙啊. 思路 考虑对于单独的一个\(k\)如何计算答案. 与"赛道修建"非常相似,但那题要求边,这题要求点,所以更加简单. 在每一个点贪心地 ...

  4. BZOJ.4320.[ShangHai2006]Homework(根号分治 分块)

    BZOJ \(\mathbb{mod}\)一个数\(y\)的最小值,可以考虑枚举剩余系,也就是枚举区间\([0,y),[y,2y),[2y,3y)...\)中的最小值(求后缀最小值也一样)更新答案,复 ...

  5. BZOJ3351: [ioi2009]Regions(根号分治)

    题意 题目链接 Sol 很神仙的题 我们考虑询问(a, b)(a是b的祖先),直接对b根号分治 如果b的出现次数\(< \sqrt{n}\),我们可以直接对每个b记录下与它有关的询问,这样每个询 ...

  6. [CF587F]Duff is Mad[AC自动机+根号分治+分块]

    题意 给你 \(n\) 个串 \(s_{1\cdots n}\) ,每次询问给出 \(l,r,k\) ,问在 \(s_{l\cdots r}\) 中出现了多少次 \(s_k\) . \(n,q,\su ...

  7. [CF1039D]You Are Given a Tree[贪心+根号分治]

    题意 给你\(n\)个点的树,其中一个简单路径的集合被称为\(k\)合法当且仅当树的每个节点最多属于一条路径,且每条路径包含\(k\)个节点.对于每个\(k(k \in [1,n])\),输出最多的\ ...

  8. CF1039D You Are Given a Tree 根号分治,贪心

    CF1039D You Are Given a Tree LG传送门 根号分治好题. 这题可以整体二分,但我太菜了,不会. 根号分治怎么考虑呢?先想想\(n^2\)暴力吧.对于每一个要求的\(k\), ...

  9. 【bzoj5206】[Jsoi2017]原力 根号分治+STL-map

    题目描述 一个原力网络可以看成是一个可能存在重边但没有自环的无向图.每条边有一种属性和一个权值.属性可能是R.G.B三种当中的一种,代表这条边上原力的类型.权值是一个正整数,代表这条边上的原力强度.原 ...

随机推荐

  1. PRD文档怎么写

    昨天学习PMP的相关文档,正好看到里面讲的PRD文档是怎么写的 就把一些学习过程,思维方式,还有用到的工具给记录下来 方便自己以后需要的时候,再去查阅,再读这个教程的时候,我顺便用脑图画了一下 脑图工 ...

  2. Mongodb Windows 集群

    我在一台Windows机器下搭建了一个 Replica Sets + Sharding 测试集群环境,以此作为我后续对于Mongodb更进一步学习的实验平台. 只有一台windows机器,配置方案:1 ...

  3. jboss-as- 7.1.1.Final配置jndi数据源

    初次使用jboss7.1.1.final部署项目,遇到了很多困难,最终通过查看官方文档和网上资料得以解决,特此记录一下. error information 2016-05-12 12:53:20 J ...

  4. pt-osc原理、限制、及与原生online-ddl比较

    1. pt-osc工作过程 创建一个和要执行 alter 操作的表一样的新的空表结构(是alter之前的结构) 在新表执行alter table 语句(速度应该很快) 在原表中创建触发器3个触发器分别 ...

  5. python基础学习6----字符串操作

    一.重复输出字符串 print('hello'*20)#输出20个hello 二.通过索引获取字符串中字符 print('helloworld'[2:])#输出lloworld 三.关键字 in pr ...

  6. skype客户端搜不到联系人解决办法

    1.确认skype客户端登陆的配置信息 按住Ctrl 键不放,右击右下角任务栏 skype 图标,选择:配置信息,确认skype的:GAL搜索或基于服务器的搜索为:基于服务器的搜索,如下图所示: 2. ...

  7. 使用Index()+Match()函数实现更为灵活的VLookUp()

    上一篇 http://www.cnblogs.com/-SANG/p/8407017.html 文章中已经介绍了vlookup的用法. 今天要使用index+match实现更为灵活的vlookup 先 ...

  8. SDN 第四次上机作业

    1.建立以下拓扑,并连接上ODL控制器. 2.利用ODL下发流表,使得h3在10s内ping不通h1,10s后恢复. 3.借助Postman通过ODL的北向接口下发流表,再利用ODL北向接口查看已下发 ...

  9. 将jar包添加到maven仓库

    Maven资源库配置 访问http://mvnrepository.com/,在搜索栏中输入你要搜索的 JAR 包的关键字 例如下载ImpalaJDBC41这个jar包   选择你想要下载的Jar包版 ...

  10. 【PyCharm疑问】在pycharm中带有中文时,有时会导致程序判断错误,是何原因?

    1.会导致程序打印false错误的代码如下: # -*- coding:utf-8 -*- import os import sys from uiautomator import device as ...