bzoj 4358: permu (莫队+栈||KD-tree||莫队+线段树)
来源:互联网 发布:腾讯云与阿里云 编辑:程序博客网 时间:2024/06/03 23:37
题目描述
传送门
题目大意:给出一个长度为n的排列P(P1,P2,…Pn),以及m个询问。每次询问某个区间[l,r]中,最长的值域
连续段长度。
题解1:莫队+线段树
用权值线段树维护区间的连续最大长度,左端连续最长,右端连续最长。
应该是比较好想,好写,好调的做法。
时间复杂度
代码1
#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#define N 50003using namespace std;int n,m,a[N],belong[N],block,ans[N],pos[N];struct data{ int id,x,y,key;}q[N];struct node{ int ls,rs,tr,len;}tree[N*4];int read(){ char c=getchar(); int x=0; while (c<'0'||c>'9') c=getchar(); while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x;}inline bool operator <(const data &a,const data &b){ return a.key<b.key||a.key==b.key&&((a.y<b.y)^(a.key&1));}inline void update(int now){ node *T=tree+now,*L=tree+(now<<1),*R=tree+(now<<1|1); T->tr=max(L->tr,R->tr); T->tr=max(L->rs+R->ls,T->tr); T->ls=L->ls+(L->ls==L->len)*R->ls; T->rs=R->rs+(R->rs==R->len)*L->rs;}inline void pointchange(int x){ int t=pos[x]; tree[t].ls=tree[t].rs=(tree[t].tr^=1); while (t!=1) update(t=t>>1);}inline void build(int now,int l,int r){ tree[now].len=r-l+1; if (l==r) { pos[l]=now; return; } int mid=(l+r)/2; build(now<<1,l,mid); build(now<<1|1,mid+1,r);}int main(){ freopen("a.in","r",stdin); freopen("my.out","w",stdout); n=read(); m=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=m;i++) q[i].x=read(),q[i].y=read(),q[i].id=i,q[i].key=sqrt(q[i].x); sort(q+1,q+m+1); build(1,1,n); int l,r; l=r=1; pointchange(a[1]); for (int i=1;i<=m;++i) { while (l<q[i].x) pointchange(a[l++]); while (l>q[i].x) pointchange(a[--l]); while (r>q[i].y) pointchange(a[r--]); while (r<q[i].y) pointchange(a[++r]); ans[q[i].id]=tree[1].tr; } for (int i=1;i<=m;i++) printf("%d\n",ans[i]);}
题解2:莫队+栈
依然是用莫队,可以终于可以不用线段树了。
将左端点分块,每个块中的右端点从小到大有序。对于左端点在一个块中的一起处理。
刚开始将莫队的左右端点都定位在块的右端点。
对于每个权值的数维护两个参ls,rs,表示向左,右延伸的最长距离。
然后用
如果当前询问的右端点<当前的右端点,那么就将当前的右端点后移。并按照上述方式更新。
然后我们考虑当前询问的左端点到还不在当前区间中的点的贡献。因为左端点的前后移动是不固定的,所以我们每次加入这些点的贡献,计算出当前询问的贡献,然后需要再回撤这些操作。保证每次左端点都停在块的右端点。
因为同一块的左端点的移动区间不超过
代码2
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define N 100003using namespace std;int c[N],st[N],st1[N],ls[N],rs[N],n,m,block,belong[N],ans[N];struct data{ int l,r,id;}q[N];int cmp(data a,data b){ return belong[a.l]<belong[b.l]||belong[a.l]==belong[b.l]&&a.r<b.r;}int main(){ freopen("a.in","r",stdin); freopen("my.out","w",stdout); scanf("%d%d",&n,&m); block=sqrt(n); for (int i=1;i<=n;i++) scanf("%d",&c[i]); for (int i=1;i<=n;i++) belong[i]=(i-1)/block+1; for (int i=1;i<=m;i++) { scanf("%d%d",&q[i].l,&q[i].r); q[i].id=i; } sort(q+1,q+m+1,cmp); int l,r,ans1; for (int i=1;i<=m;i++) { if (belong[q[i].l]!=belong[q[i-1].l]) { memset(ls,0,sizeof(ls)); memset(rs,0,sizeof(rs)); l=r=belong[q[i].l]*block; ans1=0; } while (r<q[i].r) { ++r; ls[c[r]]=ls[c[r]-1]+1; rs[c[r]]=rs[c[r]+1]+1; int t=ls[c[r]]+rs[c[r]]-1; rs[c[r]-ls[c[r]]+1]=t; ls[c[r]+rs[c[r]]-1]=t; ans1=max(ans1,t); } int tmp=ans1,top=0; for (int j=q[i].l;j<=min(q[i].r,l);j++) { ls[c[j]]=ls[c[j]-1]+1; rs[c[j]]=rs[c[j]+1]+1; int t=ls[c[j]]+rs[c[j]]-1; int ll=c[j]-ls[c[j]]+1; int rr=c[j]+rs[c[j]]-1; st[++top]=ll; st1[top]=rs[ll]; st[++top]=rr; st1[top]=ls[rr]; rs[ll]=t; ls[rr]=t; tmp=max(tmp,t); } for (int j=top;j>=1;j--) { if (j&1) rs[st[j]]=st1[j]; else ls[st[j]]=st1[j]; } for (int j=q[i].l;j<=min(q[i].r,l);j++) ls[c[j]]=rs[c[j]]=0; ans[q[i].id]=tmp; } for (int i=1;i<=m;i++) printf("%d\n",ans[i]);}
题解3:KD-tree
将每个询问的左右端点看做点对(x,y),加入KD-tree
然后从1到n依次用这些数取更新包含他原本所在位置的区间。
对于KD-tree中的每个节点需要维护六个与更新有关的参数,具体的写法和bzoj 3064是一样的,只不过那个是线段树,这个是KD-tree,反正都是pushdown,就不详细赘述了。
注意每个不包含当前数所在位置的区间,当前连续的长度都要清零。
时间复杂度
代码3
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define N 100003using namespace std;int a[N],pos[N],n,m,cmpd,ans[N],root,T[2];struct data{ int d[2],mx[2],mn[2],l,r,id; int cover,add,at,max,len,ct;}tr[N];bool operator <(data a,data b){ return a.d[cmpd]<b.d[cmpd];}int read(){ char c=getchar(); int x=0; while (c<'0'||c>'9') c=getchar(); while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x;}void update(int now){ int l=tr[now].l; int r=tr[now].r; for (int i=0;i<=1;i++) { if (l) tr[now].mx[i]=max(tr[now].mx[i],tr[l].mx[i]),tr[now].mn[i]=min(tr[now].mn[i],tr[l].mn[i]); if (r) tr[now].mx[i]=max(tr[now].mx[i],tr[r].mx[i]),tr[now].mn[i]=min(tr[now].mn[i],tr[r].mn[i]); }}int build(int l,int r,int d){ cmpd=d; int mid=(l+r)/2; nth_element(tr+l,tr+mid,tr+r+1); for (int i=0;i<=1;i++) tr[mid].mx[i]=tr[mid].mn[i]=tr[mid].d[i]; tr[mid].cover=-1; tr[mid].ct=-1; if (l<mid) tr[mid].l=build(l,mid-1,d^1); if (r>mid) tr[mid].r=build(mid+1,r,d^1); update(mid); return mid;}void pushdown(int now){ T[0]=tr[now].l; T[1]=tr[now].r; for (int i=0;i<=1;i++) { int x=T[i]; if(!x) continue; tr[x].max=max(tr[x].max,max(tr[now].ct,tr[x].len+tr[now].at)); if (tr[x].cover==-1) tr[x].at=max(tr[x].at,tr[now].at+tr[x].add); else tr[x].ct=max(tr[x].ct,tr[x].cover+tr[now].at); if (tr[now].add) { tr[x].len+=tr[now].add; if (tr[x].cover==-1) tr[x].add+=tr[now].add; else tr[x].cover+=tr[now].add; } if (tr[now].cover!=-1) { tr[x].cover=tr[x].len=tr[now].cover; tr[x].add=0; } tr[x].ct=max(tr[x].ct,max(tr[x].cover,tr[now].ct)); tr[x].at=max(tr[x].at,tr[x].add); } tr[now].at=tr[now].add=0; tr[now].cover=tr[now].ct=-1;}void change(int now,int x){ pushdown(now); if (tr[now].mx[0]<=x&&x<=tr[now].mn[1]) { tr[now].len++; tr[now].add++; tr[now].at++; tr[now].max=max(tr[now].max,tr[now].len); return; } if (tr[now].mx[1]<x||tr[now].mn[0]>x) { tr[now].cover=tr[now].ct=tr[now].len=0; return; } if (tr[now].d[0]<=x&&x<=tr[now].d[1]) { tr[now].len++; tr[now].max=max(tr[now].max,tr[now].len); } else tr[now].len=0; if(tr[now].l) change(tr[now].l,x); if(tr[now].r) change(tr[now].r,x);}void dfs(int now){ pushdown(now); if (tr[now].l) dfs(tr[now].l); if (tr[now].r) dfs(tr[now].r);}int main(){ freopen("a.in","r",stdin); freopen("my.out","w",stdout); n=read(); m=read(); for (int i=1;i<=n;i++) a[i]=read(),pos[a[i]]=i; for (int i=1;i<=m;i++) tr[i].d[0]=read(),tr[i].d[1]=read(),tr[i].id=i; root=build(1,m,0); for (int i=1;i<=n;i++) change(root,pos[i]); dfs(root); for (int i=1;i<=m;i++) ans[tr[i].id]=tr[i].max; for (int i=1;i<=m;i++) printf("%d\n",ans[i]);}
- bzoj 4358: permu (莫队+栈||KD-tree||莫队+线段树)
- bzoj4358 permu(莫队+线段树||莫队+并查集+分块)
- [BZOJ]4605 崂山白花蛇草水 线段树套KD-Tree
- bzoj 2850: 巧克力王国 (KD-tree)
- bzoj 4066: 简单题 (KD-tree)
- bzoj 2683: 简单题 (KD-tree)
- bzoj 2626: JZPFAR (KD-tree)
- [BZOJ][KD-tree]2626: JZPFAR
- KD(kd tree)树介绍
- bzoj 2648: SJY摆棋子 (KD-tree)
- bzoj 1941: [Sdoi2010]Hide and Seek (KD-tree)
- bzoj 3053: The Closest M Points (KD-tree)
- bzoj 4520: [Cqoi2016]K远点对(KD-tree)
- bzoj 3489: A simple rmq problem (KD-tree)
- KD Tree 新知选作(BZOJ 2850)
- bzoj 4154: [Ipsc2015]Generating Synergy (KD-tree)
- bzoj 2648: SJY摆棋子(kd tree)
- HDU5809(KD-tree)
- 问题复盘的必要性
- Tensorflow Serving 模型部署和服务
- python文件去除重复的代码示例
- 领域模型
- 欢迎使用CSDN-markdown编辑器
- bzoj 4358: permu (莫队+栈||KD-tree||莫队+线段树)
- 文章标题9
- Mybatis中javaType和jdbcType对应关系
- CorelDRAW 缩略图简单解决办法
- 关于各个测试阶段的测试总结
- 【Spring学习11】PropertyPlaceholderConfigurer应用
- mybatis向mysql插入数据后返回插入的主键值
- 文章标题10
- Android项目build.gradle多渠道&完整版