P6666 [清华集训2016] 数据交互 题解
P6666 [清华集训2016] 数据交互 题解
###简要题意:
n个点的树,m次操作,分别为添加一条路径$(u_i,v_i,w_i)$,和撤消一条路径,每一次操作后求出一条路径使得与这条路径有交的路径的权值和最大
。
###
题解:
先考虑如何表示所有与一条路径(记为$(u,v)$)有交的路径(记为$(x,y)$)
1.$\mathrm{LCA}(x,y)\in(u,v)$且$\mathrm{LCA}(x,y)\ne \mathrm{LCA}(u,v)$
2.$\mathrm{LCA}(u,v)\in(x,y)$
于是我们可以记$w_i$表示所有$\mathrm{LCA}(u,v)=i$的权值和,$g_i$表示所有 $i\in(u,v)$的路径的权值和。然后我们可以把一条路径有交的权值和写成非常漂亮的形式:路径上除了 $\rm LCA$的$w_i$和$g_{\mathrm{LCA}}$。
这样每次修改时就只用改$w_{\mathrm{LCA}}$和其他点的$g_i$的值。
首先我们给每个点 v 开一个可删除堆表示v的虚子树中到 v 的最长链,再开一个全局的可删除堆记录每条重链贡献的答案。
我们发现,一条路径可以看成是重链上的$u,v$两点(其中$u$是$\mathrm{LCA}$),以及这两点分别向虚子树伸出去的一条最长链(可以为空)。它的权值为这条链的$w_i$之和再加上$g_u$,当$u$等于$v$的时候,我们需要找最长链和次长链。
然后我们发现这就是一个最大子段和的问题。对于线段树上的每一个节点,我们维护:
$maxl$:从前节点包含的区间最左边(深度最小)的结点开始的最长链。
$maxr$: 从前节点包含的区间最右边(深度最小)的结点开始的最长链。
$maxn$: 当前区间的答案
$sum$: 当前区间的$w_i$之和
一条重链的链顶的最长链就是这条重链对应的$maxl$。
在修改的时候,我们先删除$lca$以上$log$条重链对答案的贡献,然后修改链上点的$g$和$lca$的$w$,再更新答案。
代码:(略微有点长)
``
#include<bits/stdc++.h> #define ll long long #define mid ((l+r)>>1) #define ls (rt<<1) #define rs (rt<<1|1) using namespace std; inline int read(){ int s=0; char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar(); return s; } inline void write(ll x){ if(x>=10)write(x/10); putchar(x%10+48); } const int N=100501; int n,m; vector<int>e[N]; int fa[N],dep[N],tp[N],tot,dfn[N],siz[N],son[N],bot[N],id[N]; struct HEAP{ priority_queue<ll>del,q; inline void POP(){ while(del.size()&&del.top()==q.top()){ del.pop(),q.pop(); } } inline void PUSH(ll x){ POP(); q.push(x); } inline void DEL(ll x){ del.push(x); } inline ll fi(){ POP(); return q.top(); } inline ll se(){ ll x=fi(); DEL(x); ll y=fi(); PUSH(x); return y; } }ANS,q[N]; struct node{ int l,r; ll maxl,maxr,maxn,sum,lz; node(){l=r=maxl=maxr=maxn=sum=lz=0;} }; node operator +(const node &a,const node &b){ node c; c.l=a.l,c.r=b.r; c.maxn=max(max(a.maxn,b.maxn),a.maxr+b.maxl); c.maxl=max(a.maxl,a.sum+b.maxl); c.maxr=max(b.maxr,b.sum+a.maxr); c.sum=a.sum+b.sum; return c; } struct SEG{ node t[N<<2]; inline void upd(int rt,int p){ int x=id[p]; ll fi=q[x].fi(),se=q[x].se(); t[rt].maxl=fi+t[rt].sum; t[rt].maxr=fi+t[rt].sum+t[rt].lz; t[rt].maxn=fi+se+t[rt].sum+t[rt].lz; } inline void build(int rt,int l,int r){ if(l==r){ upd(rt,l); return; } build(ls,l,mid),build(rs,mid+1,r); t[rt]=t[ls]+t[rs]; } inline void psh(int rt,int x){ t[rt].maxn+=x,t[rt].maxr+=x,t[rt].lz+=x; } inline void pshlz(int rt){ if(t[rt].lz){ psh(ls,t[rt].lz),psh(rs,t[rt].lz); t[rt].lz=0; } } inline void modify(int rt,int l,int r,int L,int R,ll x){ if(L<=l&&r<=R){ psh(rt,x); return; } pshlz(rt); if(L<=mid)modify(ls,l,mid,L,R,x); if(mid<R)modify(rs,mid+1,r,L,R,x); t[rt]=t[ls]+t[rs]; } inline void modify(int rt,int l,int r,int x,ll p){ t[rt].sum+=p; if(l==r){ t[rt].maxr+=p,t[rt].maxn+=p,t[rt].maxl+=p; return; } pshlz(rt); if(x<=mid)modify(ls,l,mid,x,p); else modify(rs,mid+1,r,x,p); t[rt]=t[ls]+t[rs]; } inline void change(int rt,int l,int r,int x){ if(l==r){ upd(rt,x); return; } pshlz(rt); if(x<=mid)change(ls,l,mid,x); else change(rs,mid+1,r,x); t[rt]=t[ls]+t[rs]; } inline node query(int rt,int l,int r,int L,int R){ if(L<=l&&r<=R)return t[rt]; pshlz(rt); if(L>mid)return query(rs,mid+1,r,L,R); else if(R<=mid)return query(ls,l,mid,L,R); else return query(ls,l,mid,L,mid)+query(rs,mid+1,r,mid+1,R); } }T; struct queryoption{ int x,y,w; }op[N]; inline void dfs(int x){ siz[x]=1; for(auto y:e[x]){ if(y!=fa[x]){ fa[y]=x; dep[y]=dep[x]+1; dfs(y); siz[x]+=siz[y]; if(siz[y]>siz[son[x]])son[x]=y; } } } inline void dfs1(int x,int topp){ dfn[x]=++tot; id[tot]=x; tp[x]=topp; bot[x]=x; if(son[x])dfs1(son[x],topp),bot[x]=bot[son[x]]; for(auto y:e[x]){ if(y!=fa[x]&&y!=son[x])dfs1(y,y); } } inline int get_lca(int u,int v){ while(tp[u]!=tp[v]){ if(dep[tp[u]]<dep[tp[v]])swap(u,v); u=fa[tp[u]]; } return dep[u]<dep[v]?u:v; } inline void add(int u,int v){ node c; while(tp[u]!=tp[v]){ if(dep[tp[u]]<dep[tp[v]])swap(u,v); c=T.query(1,1,n,dfn[tp[u]],dfn[bot[u]]); ANS.PUSH(c.maxn); u=fa[tp[u]]; } c=T.query(1,1,n,dfn[tp[u]],dfn[bot[u]]); ANS.PUSH(c.maxn); } inline void del(int u,int v){ node c; while(tp[u]!=tp[v]){ if(dep[tp[u]]<dep[tp[v]])swap(u,v); c=T.query(1,1,n,dfn[tp[u]],dfn[bot[u]]); ANS.DEL(c.maxn); u=fa[tp[u]]; } c=T.query(1,1,n,dfn[tp[u]],dfn[bot[u]]); ANS.DEL(c.maxn); } inline void modify(int u,int v,int w){ while(tp[u]!=tp[v]){ if(dep[tp[u]]<dep[tp[v]])swap(u,v); T.modify(1,1,n,dfn[tp[u]],dfn[u],w); u=fa[tp[u]]; } if(dep[u]>dep[v])swap(u,v); T.modify(1,1,n,dfn[u],dfn[v],w); } inline void solve(int u,int v,int w){ int lca=get_lca(u,v); node c; for(int i=tp[lca];i;i=tp[fa[i]]){ c=T.query(1,1,n,dfn[i],dfn[bot[i]]); if(fa[i])q[fa[i]].DEL(c.maxl); if(i!=tp[lca]){ ANS.DEL(c.maxn); } } del(u,v); T.modify(1,1,n,dfn[lca],w); modify(u,v,w); modify(lca,lca,-w); add(u,v); for(int i=tp[lca];i;i=tp[fa[i]]){ c=T.query(1,1,n,dfn[i],dfn[bot[i]]); if(fa[i])q[fa[i]].PUSH(c.maxl),T.change(1,1,n,dfn[fa[i]]); if(i!=tp[lca]){ ANS.PUSH(c.maxn); } } } int main(){ n=read(),m=read(); for(int i=1;i<n;i++){ int x=read(),y=read(); e[x].push_back(y),e[y].push_back(x); } for(int i=1;i<=n;i++)q[i].PUSH(0),q[i].PUSH(0); dfs(1); dfs1(1,1); for(int i=1;i<=n;i++)if(i==tp[i])ANS.PUSH(0); char ch; T.build(1,1,n); for(int i=1;i<=m;i++){ while(ch=getchar(),ch!='-'&&ch!='+'); if(ch=='+'){ op[i].x=read(),op[i].y=read(),op[i].w=read(); solve(op[i].x,op[i].y,op[i].w); } else{ int x=read(); solve(op[x].x,op[x].y,-op[x].w); } write(ANS.fi()); puts(""); } return 0; }