Loading [MathJax]/jax/element/mml/optable/BasicLatin.js

[cf1495F]Squares

nexi=min(即i的第2类边),若不存在此类jnex_{i}=n+1

建一棵树,其以0为根,且1\le i\le n的父亲为\max_{j<i,p_{i}<p_{j}}j(不存在则为0),以下记作fa_{i}

每一次选择(i,nex_{i}),都可以看作有一个收益\Delta_{i}=b_{i}-\sum_{j=i}^{nex_{i}-1}a_{j}

问题也可以看作选择若干个节点p_{1}<p_{2}<...<p_{k},使得nex_{p_{i}}\le p_{i+1}(p_{i},nex_{p_{i}})S无公共点,在此条件下最小化\sum_{i=1}^{k}\Delta_{p_{i}}+\sum_{i=1}^{n}a_{i}(后者为常数,以下忽略)

考虑(i,nex_{i}),实际上这些点恰为以i为根的子树中的点(不包括i

(注意这棵树中,若ij的祖先,则必然有i<j

由此,条件也即变为p_{i}之间两两不成祖先-后代关系,且p_{i}子树内(不包括p_{i})不能含有S中的点

(关于这两点性质,可以简单分类讨论地分析一下,具体这里就省略了)

f_{i}表示以i为根的子树内,选择若干个两两不成祖先-后代关系的点,\sum\Delta_{p_{i}}之和的最大值(忽略S的限制),对于f显然可以树形dp计算,复杂度为o(n)

问题即求所有极浅的点,满足其子树内(不包括自己)没有S中的元素,这些点的f之和

更具体的,令H为包含0以及S中所有元素的父亲的最小连通块,“满足其子树内(不包括自己)没有S中的元素”即等价于不在H中,因此问题即求\sum_{x\notin H,fa_{x}\in H}f_{x}

g_{x}=\sum_{fa_{y}=x}f_{y},枚举fa_{x}并用g_{x}减去x\in H的部分,即求\sum_{x\in H}(g_{x}-\sum_{fa_{y}=x,y\in H}f_{y})

将两部分拆开,也即\sum_{x\in H}g_{x}-\sum_{x\in H,x\ne 0}f_{x}=g_{0}+\sum_{x\in H,x\ne 0}g_{x}-f_{x}(前者为常数,以下忽略)

ifa_{i}的边权为g_{i}-f_{i},也即求H中所有边权之和

考虑将0以及S中所有元素的父亲按照dfs序排序,依次为p_{1},p_{2},...,p_{k},答案即\frac{\sum_{i=1}^{k}dis(p_{i},p_{i\ mod\ k+1})}{2}

(关于这个的正确性,这样从p_{1}->p_{2}->...->p_{k}H中每一条边必然被经过恰好两次)

关于这个,用线段树或set维护即可,复杂度为o((n+q)\log n)

复制代码
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 200005
  4 #define ll long long
  5 #define L (k<<1)
  6 #define R (L+1)
  7 #define mid (l+r>>1)
  8 struct Edge{
  9     int nex,to;
 10 }edge[N];
 11 int E,n,q,x,p[N],head[N],st[N],dfn[N],idfn[N],sh[N],vis[N],fa[N][21],f[N<<2];
 12 ll sum,ans,a[N],b[N],g[N],dp[N],dep[N];
 13 void add(int x,int y){
 14     edge[E].nex=head[x];
 15     edge[E].to=y;
 16     head[x]=E++;
 17 }
 18 int lca(int x,int y){
 19     if (sh[x]<sh[y])swap(x,y);
 20     for(int i=20;i>=0;i--)
 21         if (sh[fa[x][i]]>=sh[y])x=fa[x][i];
 22     if (x==y)return x;
 23     for(int i=20;i>=0;i--)
 24         if (fa[x][i]!=fa[y][i]){
 25             x=fa[x][i];
 26             y=fa[y][i];
 27         }
 28     return fa[x][0];
 29 }
 30 ll dis(int x,int y){
 31     return dep[x]+dep[y]-2*dep[lca(x,y)];
 32 }
 33 ll dis_dfn(int x,int y){
 34     return dis(idfn[x],idfn[y]);
 35 }
 36 void dfs1(int k){
 37     for(int i=head[k];i!=-1;i=edge[i].nex){
 38         dfs1(edge[i].to);
 39         g[k]+=dp[edge[i].to];
 40     }
 41     dp[k]=min(g[k],b[k]);
 42 }
 43 void dfs2(int k,int f,int s1,ll s2){
 44     idfn[x]=k;
 45     dfn[k]=x++;
 46     sh[k]=s1;
 47     dep[k]=s2;
 48     fa[k][0]=f;
 49     for(int i=1;i<=20;i++)fa[k][i]=fa[fa[k][i-1]][i-1];
 50     for(int i=head[k];i!=-1;i=edge[i].nex)dfs2(edge[i].to,k,s1+1,s2+g[edge[i].to]-dp[edge[i].to]);
 51 }
 52 void update(int k,int l,int r,int x,int y){
 53     f[k]+=y;
 54     if (l==r)return;
 55     if (x<=mid)update(L,l,mid,x,y);
 56     else update(R,mid+1,r,x,y);
 57 }
 58 int query(int k,int l,int r,int x){
 59     if (l==r)return f[k];
 60     if (x<=mid)return query(L,l,mid,x);
 61     return query(R,mid+1,r,x);
 62 }
 63 int query_pre(int k,int l,int r,int x){
 64     if ((!f[k])||(l>x))return -1;
 65     if (l==r)return l;
 66     int ans=query_pre(R,mid+1,r,x);
 67     if (ans>=0)return ans;
 68     return query_pre(L,l,mid,x);
 69 }
 70 int query_nex(int k,int l,int r,int x){
 71     if ((!f[k])||(r<x))return -1;
 72     if (l==r)return l;
 73     int ans=query_nex(L,l,mid,x);
 74     if (ans>=0)return ans;
 75     return query_nex(R,mid+1,r,x);
 76 }
 77 int query_pre(int x){
 78     int ans=query_pre(1,0,n,x-1);
 79     if (ans>=0)return ans;
 80     return query_pre(1,0,n,n);
 81 }
 82 int query_nex(int x){
 83     int ans=query_nex(1,0,n,x+1);
 84     if (ans>=0)return ans;
 85     return query_nex(1,0,n,0);
 86 }
 87 ll calc(int k){
 88     int x=query_pre(k),y=query_nex(k);
 89     return dis_dfn(x,k)+dis_dfn(y,k)-dis_dfn(x,y);
 90 }
 91 int main(){
 92     scanf("%d%d",&n,&q);
 93     for(int i=1;i<=n;i++)scanf("%d",&p[i]);
 94     for(int i=1;i<=n;i++){
 95         scanf("%lld",&a[i]);
 96         a[i]+=a[i-1];
 97     }
 98     for(int i=1;i<=n;i++)scanf("%lld",&b[i]);
 99     for(int i=n;i;i--){
100         while ((st[0])&&(p[st[st[0]]]<p[i]))st[0]--;
101         if (!st[0])b[i]-=a[n]-a[i-1];
102         else b[i]-=a[st[st[0]]-1]-a[i-1];
103         st[++st[0]]=i;
104     }
105     memset(head,-1,sizeof(head));
106     st[0]=0;
107     for(int i=1;i<=n;i++){
108         while ((st[0])&&(p[st[st[0]]]<p[i]))st[0]--;
109         add(st[st[0]],i);
110         st[++st[0]]=i;
111     }
112     dfs1(0);
113     dfs2(0,0,0,0);
114     sum=g[0]+a[n];
115     update(1,0,n,0,1);
116     for(int i=1;i<=q;i++){
117         scanf("%d",&x);
118         int y=dfn[fa[x][0]];
119         if (!vis[x]){
120             update(1,0,n,y,1);
121             if (query(1,0,n,y)==1)ans+=calc(y);
122         }
123         else{
124             update(1,0,n,y,-1);
125             if (!query(1,0,n,y))ans-=calc(y);
126         }
127         vis[x]^=1;
128         printf("%lld\n",sum+ans/2);
129     }
130 }
View Code
复制代码

 

posted @   PYWBKTDA  阅读(83)  评论(0编辑  收藏  举报
编辑推荐:
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
阅读排行:
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 数据库服务器 SQL Server 版本升级公告
· C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)
· 程序员常用高效实用工具推荐,办公效率提升利器!
点击右上角即可分享
微信分享提示