1 条题解
-
0
自动搬运
来自洛谷,原作者为

DaiRuiChen007
白鸟白鸟 不要回头望 你要替我飞去那地方 一去那地方 那是你我共同故乡搬运于
2025-08-24 22:17:29,当前版本为作者最后更新于2023-09-10 03:05:36,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
P6107 题解
题目大意
给定序列 ,其中 ,对于所有 与 和 连双向边。
次修改使 ,每次求有多少个大小为 的点集存在六元环。
数据范围:。
思路分析
首先建大根笛卡尔树,注意到笛卡尔树上的每个大小为 的连通块,加上联通块根节点的左右父亲必定构成一个六元环,且不存在其他可能构成方式。
因此答案等于笛卡尔树上大小为 的连通块数量,但是不包含树根,因为 之间不连边。
注意到每次 变大相当于在笛卡尔树上不停上旋,暴力更新可以做到 。
但是复杂度过高,注意到 要么向左上旋要么向右上旋,通过势能分析可以证明旋转方向改变次数总和为 级别。
而注意到 不停左旋到一个点上,树结构总的变化只有 ,更新的点数也只有 。
问题变成如何快速求 不断左旋会到哪里,先考虑这一段链的根在哪里,即求出 左边 的第一个位置 , 就是这段链的根。
- 如果 ,那么直接旋转到根。
- 否则找到 右边第一个 的位置 ,转到 的左儿子即可。
右旋情况同理,为了减少常数,建议使用 zkw 线段树实现。
时间复杂度 。
代码呈现
#include<bits/stdc++.h> #define ll long long using namespace std; const int MAXN=5e5+5; int n,q,rt; struct SegmentTree { const int N=1<<19; ll tr[1<<20]; inline void add(int x,int v) { tr[x+=N]+=v; for(x>>=1;x;x>>=1) tr[x]=max(tr[x<<1],tr[x<<1|1]); } inline int lpos(int x,ll k) { for(x+=N+1;x>1;x>>=1) if((x&1)&&tr[x^1]>=k) break; if(x==1) return 0; for(x^=1;x<=N;) x=(tr[x<<1|1]>=k)?(x<<1|1):(x<<1); return x-N; } inline int rpos(int x,ll k) { for(x+=N-1;x>1;x>>=1) if((~x&1)&&tr[x^1]>=k) break; if(x==1) return n+1; for(x^=1;x<=N;) x=(tr[x<<1]>=k)?(x<<1):(x<<1|1); return x-N; } } TR; ll a[MAXN],dp[MAXN][5],ans=0; inline int cmp(int x,int y) { return x<y?a[x]<a[y]:a[x]<=a[y]; } int ch[MAXN][2],fa[MAXN]; inline void upd(int u) { if(!u) return ; ans-=dp[u][4]; bool ok=false; int ls=ch[u][0],rs=ch[u][1],cur; cur=dp[rs][1]+dp[ls][1]; ok|=dp[u][2]!=cur,dp[u][2]=cur; cur=dp[rs][2]+dp[ls][1]*dp[rs][1]+dp[ls][2]; ok|=dp[u][3]!=cur,dp[u][3]=cur; cur=dp[ls][3]+dp[ls][2]*dp[rs][1]+dp[ls][1]*dp[rs][2]+dp[rs][3]; ok|=dp[u][4]!=cur,dp[u][4]=cur; ans+=dp[u][4]; if(ok) upd(fa[u]); } int id[MAXN],stk[MAXN]; inline void init() { for(int i=1,tp=0;i<=n;++i) { bool add=false; while(tp&&cmp(stk[tp],i)) --tp,add=true; if(tp) ch[stk[tp]][1]=i; if(add) ch[i][0]=stk[tp+1]; stk[++tp]=i; } iota(id+1,id+n+1,1),sort(id+1,id+n+1,cmp); rt=id[n],dp[0][0]=1; for(int i=1;i<=n;++i) { int u=id[i]; fa[ch[u][0]]=fa[ch[u][1]]=id[i]; dp[u][0]=dp[u][1]=1,upd(id[i]); } } inline void link(int f,int x,int c) { ch[f][c]=x,fa[x]=x?f:0; } signed main() { scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%lld",&a[i]),TR.add(i,a[i]); init(),scanf("%d",&q); for(int x,t;q--;) { scanf("%d%d",&x,&t),a[x]+=t; while(x!=rt) { int f=fa[x]; if(cmp(x,f)) break; if(x==ch[f][0]) { int u=TR.lpos(f-1,a[f]),v=u?ch[u][1]:rt; if(cmp(v,x)) { link(f,ch[x][1],0); link(x,v,1); if(u) link(u,x,1); else rt=x,fa[x]=0; } else { int w=TR.rpos(x+1,a[x]+1),y=ch[w][0]; link(f,ch[x][1],0); link(x,y,1); link(w,x,0); } } else { int u=TR.rpos(f+1,a[f]+1),v=u<=n?ch[u][0]:rt; if(cmp(v,x)) { link(f,ch[x][0],1); link(x,v,0); if(u<=n) link(u,x,0); else rt=x,fa[x]=0; } else { int w=TR.lpos(x-1,a[x]),y=ch[w][1]; link(f,ch[x][0],1); link(x,y,0); link(w,x,1); } } upd(f),upd(x),upd(fa[x]); } TR.add(x,t); printf("%lld\n",ans-dp[rt][4]); } return 0; }
- 1
信息
- ID
- 5129
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者