1 条题解

  • 0
    @ 2025-8-24 22:17:29

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar DaiRuiChen007
    白鸟白鸟 不要回头望 你要替我飞去那地方 一去那地方 那是你我共同故乡

    搬运于2025-08-24 22:17:29,当前版本为作者最后更新于2023-09-10 03:05:36,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P6107 题解

    题目大意

    给定序列 a0an+1a_0\sim a_{n+1},其中 a0=an+1=+a_0=a_{n+1}=+\infty,对于所有 x[1,n]x\in[1,n]maxi[0,x),aiaxi\max\limits_{i\in[0,x),a_i\ge a_x}imini(x,n+1],ax<aii\min\limits_{i\in(x,n+1],a_x<a_i} i 连双向边。

    qq 次修改使 axax+ta_x\gets a_x+t,每次求有多少个大小为 66点集存在六元环。

    数据范围:n,q5×105n,q\le 5\times 10^5

    思路分析

    首先建大根笛卡尔树,注意到笛卡尔树上的每个大小为 44 的连通块,加上联通块根节点的左右父亲必定构成一个六元环,且不存在其他可能构成方式。

    因此答案等于笛卡尔树上大小为 44 的连通块数量,但是不包含树根,因为 0,n+10,n+1 之间不连边。

    注意到每次 axa_x 变大相当于在笛卡尔树上不停上旋,暴力更新可以做到 O(nq)\mathcal O(nq)

    但是复杂度过高,注意到 axa_x 要么向左上旋要么向右上旋,通过势能分析可以证明旋转方向改变次数总和为 O((n+q)logn)\mathcal O((n+q)\log n) 级别。

    而注意到 axa_x 不停左旋到一个点上,树结构总的变化只有 O(1)\mathcal O(1),更新的点数也只有 O(1)\mathcal O(1)

    问题变成如何快速求 axa_x 不断左旋会到哪里,先考虑这一段链的根在哪里,即求出 axa_x 左边 ax\ge a_x 的第一个位置 uuv=rsuv=rs_u 就是这段链的根。

    • 如果 axava_x\ge a_v,那么直接旋转到根。
    • 否则找到 xx 右边第一个 >ax>a_x 的位置 ww,转到 ww 的左儿子即可。

    右旋情况同理,为了减少常数,建议使用 zkw 线段树实现。

    时间复杂度 O((n+q)log2n)\mathcal O((n+q)\log^2n)

    代码呈现

    #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
    上传者