博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CF1039E Summer Oenothera Exhibition 根号分治,LCT,ST表
阅读量:5338 次
发布时间:2019-06-15

本文共 3032 字,大约阅读时间需要 10 分钟。

CF1039E Summer Oenothera Exhibition

根号分治好题。

可以先看我的。

题意就是给出长度为\(n\)的区间和\(q\)组询问以及一个\(w\),每次询问一个\(k\),问最少把一段给定区间划分几次可以满足每一段划分出的子区间的极差不超过\(w-k\)(以下默认\(k\)就是\(w-k\))。

这题主要有两种写法,一种是\(O(n \sqrt nlog n)\)的,一种是\(O(n^{ \frac 5 3}+n^{ \frac 4 3} log n)\)的(本文中默认了\(n\)\(q\)同阶)。

反正先考虑\(n^2\)暴力,预处理一个ST表,对于每次询问\(O(n)\)地贪心扫一遍,能划在一个子区间内就划在一个子区间内,这样贪心一定是正确的。

先讲第一种,比较好想,想到从每个点向从它开始能划到它同一个子区间内的最远的点的右边一个点(定义这个点为\(h[j]\))一条边,这时我们就想起了,可以用LCT维护答案,但是由于每次改变\(k\)值会可能更改所有点连边情况,的直接这样做是\(O(n^2 log n)\)的,连暴力都不如。考虑根号分块,先把询问离线,按\(k\)从小到大排个序,这样划分出区间的长度是单调不减的,如果所连的边的长度不超过\(\sqrt n\),就直接用LCT暴力维护,由于边的长度不超过\(\sqrt n\),对于所有点最多删边加边\(\sqrt n\)次,由于每次的复杂度都是\(log n\)的,所以总的复杂度是\(O(n \sqrt n log n)\);如果所要连的边长度超过\(\sqrt n\)了,就不连这条边;这样我们就用LCT维护了一个森林,对于森林里每棵树的贡献都可以\(O(1)\)查询,每次询问时先计算一棵树的贡献,到了树根之后就二分它的\(h[j]\),跳过去把答案++,再计算\(h[j]\)所在树的贡献。

#include
#include
#include
#include
#include
#define R register#define I inlineusing namespace std;const int S=100003,M=17,inf=0x7fffffff;char buf[1000000],*p1,*p2;I char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,S,stdin),p1==p2)?EOF:*p1++;}I int rd(){ R int f=0; R char c=gc(); while(c<48||c>57) c=gc(); while(c>47&&c<58) f=f*10+(c^48),c=gc(); return f;}struct query{int k,p,o;}q[S];struct splay{int p,d[2],s;}e[S];int a[S],b[S],l[S],f[S][M],g[S][M],h[S],m;vector
v[S];I int operator<(query x,query y){return x.k
y?x:y;}I int qmn(int x,int y){ R int i=l[y-x+1]; return min(f[x][i],f[y-(1<
>1;l
>1) qmx(x,m)-qmn(x,m)>k?r=m:l=m+1; return m;}int main() R int n=rd(),W=rd(),Q=rd(),p=sqrt(n),i,j,k,t,s,o; for(m=n+1,i=1;i<=n;++i) a[i]=f[i][0]=g[i][0]=rd(); a[m]=f[m][0]=g[m][0]=inf,l[1]=0; for(i=2;i<=m;++i) l[i]=l[i>>1]+1; for(i=1,k=2;k<=m;++i,k<<=1) for(j=1;j+k-1<=m;++j) f[j][i]=min(f[j][i-1],f[j+(k>>1)][i-1]),g[j][i]=max(g[j][i-1],g[j+(k>>1)][i-1]); for(i=1;i<=Q;++i) q[i].p=i,q[i].k=W-rd(); sort(q+1,q+Q+1); for(i=1;i<=n;++i) h[i]=i,e[i].p=i+1,v[1].push_back(i); for(i=1;i<=Q;++i){ for(o=0,t=0,s=v[i].size();t
p) b[j]=1; else h[j]=k,e[j].p=h[j],v[lower_bound(q+1,q+1+Q,(query){qmx(j,h[j])-qmn(j,h[j]),0})-q].push_back(j); } for(j=1;;j=fnd(j,q[i].k),++o){ if(!b[j]) acc(j),spl(j),o+=e[j].s-1,j=frt(j); if(j>n) break; } q[q[i].p].o=o-1; } for(i=1;i<=Q;++i) printf("%d\n",q[i].o); return 0;}

注意在实现时有一个重要的细节,删边加边的时候必须二分找它下一个可能改变它\(h[j]\)值的询问,而不能对于每次询问都把序列扫一遍,这样复杂度会被卡成\(n^2\)。例如下面的操作就是错误的。

for(i=1;i<=Q;++i){        o=0;        for(j=1;j<=n;++j)            if(!b[j]){                for(k=h[j];qmx(j,k)-qmn(j,k)<=q[i].k&&k-j<=p&&k<=n;++k);                if(k-j>p)                    b[j]=1,cut(j);                else                    if(k^h[j])                        cut(j),h[j]=k,e[j].p=h[j];            }        for(j=1;;j=fnd(j,q[i].k),++o){            if(!b[j])                acc(j),spl(j),o+=e[j].s-1,j=frt(j);            if(j>n) break;        }        q[q[i].p].o=o-1;    }

下面介绍第二种做法。

wxh太神了我看不懂。

然后Itst把wxh的做法写出来了,我就直接丢了。

转载于:https://www.cnblogs.com/cj-chd/p/10127491.html

你可能感兴趣的文章
java中常用方法
查看>>
【Programming Clip】06、07年清华计算机考研上机试题解答(个别测试用例无法通过)...
查看>>
canvas动画
查看>>
4,7周围玩家
查看>>
关于webpack升级过后不能打包的问题;
查看>>
vue - 生命周期
查看>>
Python正则表达式
查看>>
Linux进程间通信--命名管道
查看>>
UVa 10970 - Big Chocolate
查看>>
js输出
查看>>
H5多文本换行
查看>>
HAL层三类函数及其作用
查看>>
Odoo 去掉 恼人的 "上午"和"下午"
查看>>
web@h,c小总结
查看>>
java编程思想笔记(一)——面向对象导论
查看>>
Data Structure 基本概念
查看>>
Ubuntu改坏sudoers后无法使用sudo的解决办法
查看>>
NEYC 2017 游记
查看>>
[搬运] 写给 C# 开发人员的函数式编程
查看>>
Python之旅Day14 JQuery部分
查看>>