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

jun头吉吉
alive搬运于
2025-08-24 22:22:55,当前版本为作者最后更新于2022-06-12 21:45:52,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题意
给定一棵 个点的树, 次操作:
- 添加一条路径 ,权值为
- 撤回一次操作
每一次操作后求出一条路径使得与这条路径有交的路径的权值和最大。
题解
100多通过没有题解非常恐怖。来献个丑。
下面只考虑加路径操作,删路径增加一条相反数即可。
下面记 表示 在这条路径上。
首先对于一条路径 ,我们如果简洁地表示出所有与它有交的路径捏?发现有两种 满足条件:
- 且
发现所有有交的 在上面这个东西中不重不漏得被数到了一次。换成权值这个显然也是不重不漏的。于是我们可以记 表示所有 的权值和, 表示所有 的 的权值和。然后我们可以把一条路径有交的权值和写成非常漂亮的形式:路径上除了 的 的和加上 。
然后这个就可以直接做了吧。设 表示从 开始往下走最大的 和,然后转移 的时候就算一个儿子的 的最大值 和次大值 ,转移就是:
$$\begin{aligned} &f_u\leftarrow val2_u+mx\\ &ans\leftarrow val1_u+mx+cmx \end{aligned} $$这个直接做就是 了,期望得分 30pts。
然后这个东西可以 吧。我们把重链上的转移写成矩阵,每一个节点开一个
$$\begin{pmatrix} f_u\\ g_u\\ 0\end{pmatrix} =\begin{pmatrix} val2_u&-\infty& mx+val2_u\\ mx+val1_i&0&mx+cmx+val1_u\\ -\infty&\infty&0 \end{pmatrix} \times \begin{pmatrix} f_{heavy}\\ g_{heavy}\\ 0 \end{pmatrix} $$multiset记录不是重儿子的 值,记 为不是重儿子上的最大的 , 为不是重儿子的次大值,那么:这里的矩阵乘法是对应加起来然后取 。
其中 的意思和上面相同, 的意思是这条重链到当前为止的最大权值和。全局开一个
multiset记录所有重链的最大值。然后对这个矩阵我们考虑 和 的修改。
的修改其实是简单的因为只会更改一个值,修改这个值暴力更改上去即可,复杂度 。
然后 的修改需要思考一下,矩阵会区间加一个值就会比较麻烦。但是思考一下也不是很麻烦,因为:
$$\begin{pmatrix} a&-\infty&b\\ c&0&d\\ -\infty&\infty&0 \end{pmatrix}\times \begin{pmatrix} e&-\infty&f\\ g&0&h\\ -\infty&-\infty&0 \end{pmatrix} =\begin{pmatrix} a+e&-\infty&\max(a+f,b)\\ \max(e+c,g)&0&\max(c+f,h,d)\\ -\infty&-\infty&0 \end{pmatrix} $$发现区间加就是让 全部加一个值,发现乘法之后这两个位置仍然是加这个值。然后就可以打懒标记做了。复杂度 。
实现的时候为了方便可以差分成 次做,具体实现可以看代码。
代码
#include<bits/stdc++.h> #define mp make_pair #define mt make_tuple #define eb emplace_back #define pb push_back #define pc putchar #define chkmx(a,b) (a)=max((a),(b)) #define chkmn(a,b) (a)=min((a),(b)) #define fi first #define se second using namespace std; template<class T> void read(T&x){x=0;char c=getchar();bool f=0;for(;!isdigit(c);c=getchar())f^=c=='-';for(;isdigit(c);c=getchar())x=x*10+(c-'0');if(f)x=-x;} template<class T,class ...ARK>void read(T&x,ARK&...ark){read(x);read(ark...);} template<class T>void write(T x){if(x<0)pc('-'),x=-x;if(x>=10)write(x/10);pc(x%10+'0');} template<class T,class ...ARK>void write(T x,ARK...ark){write(x);pc(' ');write(ark...);} template<class ...ARK>void writeln(ARK...ark){write(ark...);pc('\n');} typedef long long ll; #define lowbit(x) ((x)&-(x)) #define mid ((l+r)>>1) #define lc (x<<1) #define rc (x<<1|1) const int N=1e5+10; int n,m; vector<int>e[N]; int fa[N],dep[N],dfn[N],sz[N],top[N],son[N],cnt,down[N]; void dfs1(int u){ dep[u]=dep[fa[u]]+1; sz[u]=1; for(auto v:e[u])if(v!=fa[u]){ fa[v]=u;dfs1(v);sz[u]+=sz[v]; if(sz[v]>sz[son[u]])son[u]=v; } } void dfs2(int u){ dfn[u]=++cnt; if(!top[u]){top[u]=down[u]=u;while(son[down[u]])down[u]=son[down[u]];} if(son[u])top[son[u]]=top[u],dfs2(son[u]); for(auto v:e[u])if(v!=fa[u]&&v!=son[u])dfs2(v); } struct mat{ // a -oo b // c 0 d //-oo -oo 0 ll a,b,c,d; mat(ll a=0,ll b=0,ll c=0,ll d=0):a(a),b(b),c(c),d(d){} friend mat operator*(mat A,mat B){ return mat( A.a+B.a, max(A.a+B.b,A.b), max(A.c+B.a,B.c), max({A.c+B.b,B.d,A.d}) ); } }; struct node{ mat mt;ll tag; }t[N<<2]; void pushtag(int x,ll v){ t[x].tag+=v; t[x].mt.c+=v; t[x].mt.d+=v; } void pushdown(int x){ if(t[x].tag) pushtag(lc,t[x].tag), pushtag(rc,t[x].tag), t[x].tag=0; } void pushup(int x){t[x].mt=t[lc].mt*t[rc].mt;} void add(int x,int l,int r,int ql,int qr,int v){ if(ql<=l&&r<=qr)return pushtag(x,v); if(r<ql||qr<l)return; pushdown(x); add(lc,l,mid,ql,qr,v); add(rc,mid+1,r,ql,qr,v); pushup(x); } void mdf(int x,int l,int r,int p,mat v){ if(l==r)return t[x].mt=v,void(); pushdown(x); if(p<=mid)mdf(lc,l,mid,p,v); else mdf(rc,mid+1,r,p,v); pushup(x); } mat qry(int x,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr)return t[x].mt; pushdown(x); if(qr<=mid)return qry(lc,l,mid,ql,qr); if(mid<ql)return qry(rc,mid+1,r,ql,qr); return qry(lc,l,mid,ql,qr)*qry(rc,mid+1,r,ql,qr); } ll get(int x,int l,int r,int p){ if(l==r)return t[x].tag; pushdown(x); if(p<=mid)return get(lc,l,mid,p); else return get(rc,mid+1,r,p); } ll val2[N]; multiset<ll>fl[N],res; mat getmat(int u){ ll v1=get(1,1,n,dfn[u]); ll v2=val2[u]; ll mx=*fl[u].rbegin(),cmx=*++fl[u].rbegin(); return mat(v2,mx+v2,mx+v1,mx+cmx+v1); } int lca(int u,int v){ while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]])swap(u,v); u=fa[top[u]]; } if(dep[u]>dep[v])return v; return u; } void addv1(int u,int w){ //从 u 到 根的路径 加 w int x=u; while(x){ mat ori=qry(1,1,n,dfn[top[x]],dfn[down[top[x]]]); ll f=max(ori.a,ori.b),g=max(ori.c,ori.d); res.erase(res.find(g)); if(fa[top[x]])fl[fa[top[x]]].erase(fl[fa[top[x]]].find(f)); x=fa[top[x]]; } x=u; while(x){ add(1,1,n,dfn[top[x]],dfn[x],w); mat now=qry(1,1,n,dfn[top[x]],dfn[down[top[x]]]); ll f=max(now.a,now.b),g=max(now.c,now.d); res.insert(g); if(fa[top[x]]){ fl[fa[top[x]]].insert(f); mdf(1,1,n,dfn[fa[top[x]]],getmat(fa[top[x]])); } x=fa[top[x]]; } } void addv2(int u,int w){ //给 u 的 v2 加上 w int x=u; while(x){ mat ori=qry(1,1,n,dfn[top[x]],dfn[down[top[x]]]); ll f=max(ori.a,ori.b),g=max(ori.c,ori.d); res.erase(res.find(g)); if(fa[top[x]]) fl[fa[top[x]]].erase(fl[fa[top[x]]].find(f)); x=fa[top[x]]; } val2[u]+=w; mdf(1,1,n,dfn[u],getmat(u)); x=u; while(x){ mat now=qry(1,1,n,dfn[top[x]],dfn[down[top[x]]]); ll f=max(now.a,now.b),g=max(now.c,now.d); res.insert(g); if(fa[top[x]]){ fl[fa[top[x]]].insert(f); mdf(1,1,n,dfn[fa[top[x]]],getmat(fa[top[x]])); } x=fa[top[x]]; } } void add(int u,int v,int w){ int l=lca(u,v); addv1(u,w);addv1(v,w);addv1(l,-w);addv1(fa[l],-w); addv2(l,w); } int x[N],y[N],w[N]; signed main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); read(n,m); for(int i=1,u,v;i<n;i++)read(u,v),e[u].pb(v),e[v].pb(u); dfs1(1);dfs2(1); for(int i=1;i<=n;i++)fl[i].insert(0),fl[i].insert(0); for(int i=1;i<=n;i++)for(auto j:e[i])if(j!=son[i]&&j!=fa[i])fl[i].insert(0); for(int i=1;i<=n;i++)if(i==top[i])res.insert(0); for(int i=1;i<=m;i++){ char op=getchar();while(op!='+'&&op!='-')op=getchar(); if(op=='+'){ read(x[i],y[i],w[i]); add(x[i],y[i],w[i]); }else{ int t;read(t); add(x[t],y[t],-w[t]); } //for(int i=1;i<=n;i++)write(get(1,1,n,dfn[i])),pc(' ');pc('\n'); writeln(*res.rbegin()); } }
- 1
信息
- ID
- 5649
- 时间
- 3000ms
- 内存
- 500MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者