令$nex_{i}=min_{i<j,p_{i}<p_{j}}j$(即$i$的第2类边),若不存在此类$j$则$nex_{i}=n+1$
建一棵树,其以0为根,且$1le ile 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$)
(注意这棵树中,若$i$为$j$的祖先,则必然有$i<j$)
由此,条件也即变为$p_{i}$之间两两不成祖先-后代关系,且$p_{i}$子树内(不包括$p_{i}$)不能含有$S$中的点
(关于这两点性质,可以简单分类讨论地分析一下,具体这里就省略了)
令$f_{i}$表示以$i$为根的子树内,选择若干个两两不成祖先-后代关系的点,$sumDelta_{p_{i}}$之和的最大值(忽略$S$的限制),对于$f$显然可以树形dp计算,复杂度为$o(n)$
问题即求所有极浅的点,满足其子树内(不包括自己)没有$S$中的元素,这些点的$f$之和
更具体的,令$H$为包含0以及$S$中所有元素的父亲的最小连通块,“满足其子树内(不包括自己)没有$S$中的元素”即等价于不在$H$中,因此问题即求$sum_{x otin H,fa_{x}in H}f_{x}$
令$g_{x}=sum_{fa_{y}=x}f_{y}$,枚举$fa_{x}$并用$g_{x}$减去$xin H$的部分,即求$sum_{xin H}(g_{x}-sum_{fa_{y}=x,yin H}f_{y})$
将两部分拆开,也即$sum_{xin H}g_{x}-sum_{xin H,x e 0}f_{x}=g_{0}+sum_{xin H,x e 0}g_{x}-f_{x}$(前者为常数,以下忽略)
令$i$到$fa_{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)$
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 ",sum+ans/2); 129 } 130 }