【UOJ #268】【清华集训2016】数据交互(动态DP)
首先一个结论是所有相交的链一定满足其中一个的在另一个的上
考虑对于每一条链
除了的点加上一个,加一个
那么一条路径的权值就是路径所有点的加上处的
考虑询问的是全局的答案
用一个可删堆存每个点作为的答案
那么就是从往下的链中选2个出来
先重链剖分
再对每一个点维护一个可删堆存所有轻儿子的往下最大权值
对于重链则是相当于是做一个类似最大子段和的东西
就是
注意到的区间加,实际上只会对一个点作为产生贡献
如果用类似线段树的最大子段和的做法,则只会影响
的变化也不改变
还要考虑由两个轻儿子拼起来的情况
具体实现可以看代码
#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
#define pb push_back
cs int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
inline char readchar(){
char ch=gc();
while(isspace(ch))ch=gc();
return ch;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=100005;
struct heap{
priority_queue<ll>a,b;
inline void push(ll x){a.push(x);}
inline void erase(ll x){b.push(x);}
inline ll top(){
while(b.size()&&a.top()==b.top())
a.pop(),b.pop();
return a.top();
}
inline ll setop(){
while(b.size()&&a.top()==b.top())
a.pop(),b.pop();
ll x=a.top();
a.pop();
if(!a.size())return a.push(x),0;
while(b.size()&&a.top()==b.top())
a.pop(),b.pop();
if(!a.size())return a.push(x),0;
ll y=a.top();a.push(x);
return y;
}
}ans,s[N];
struct node{
ll lmx,rmx,s,ans;
node(){lmx=rmx=s=ans=0;}
friend inline node operator +(cs node &a,cs node &b){
node c;
c.s=a.s+b.s;
c.lmx=max(a.lmx,a.s+b.lmx);
c.rmx=max(b.rmx,a.rmx+b.s);
c.ans=max(max(a.ans,b.ans),a.rmx+b.lmx);
return c;
}
};
struct opt{
int u,v,w;
}pt[N];
vector<int> e[N];
int siz[N],fa[N],top[N],dep[N],son[N],ed[N],in[N],dfn;
int n,m;
void dfs1(int u){
siz[u]=1;
for(int &v:e[u]){
if(v==fa[u])continue;
fa[v]=u,dep[v]=dep[u]+1;
dfs1(v),siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u,int tp){
top[u]=tp,ed[tp]=u,in[u]=++dfn;
if(son[u])dfs2(son[u],tp);
for(int &v:e[u]){
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
namespace Seg{
cs int N=::N<<2;
node s[N];ll tag[N];
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
inline void pushnow(int u,ll k){
tag[u]+=k,s[u].ans+=k,s[u].rmx+=k;
}
inline void pushdown(int u){
if(!tag[u])return;
pushnow(lc,tag[u]);
pushnow(rc,tag[u]);
tag[u]=0;
}
inline void pushup(int u){
s[u]=s[lc]+s[rc];
}
void update(int u,int l,int r,int st,int des,int k){
if(st<=l&&r<=des)return pushnow(u,k);
pushdown(u);
if(st<=mid)update(lc,l,mid,st,des,k);
if(mid<des)update(rc,mid+1,r,st,des,k);
pushup(u);
}
void updatea(int u,int l,int r,int p,int k){
if(l==r){s[u].lmx+=k,s[u].rmx+=k,s[u].ans+=k,s[u].s+=k;return;}
pushdown(u);
if(p<=mid)updatea(lc,l,mid,p,k);
else updatea(rc,mid+1,r,p,k);
pushup(u);
}
void updatep(int u,int l,int r,int p,ll k1,ll k2){
if(l==r){
s[u].lmx+=k1,s[u].rmx+=k1,s[u].ans+=k1+k2;
return;
}
pushdown(u);
if(p<=mid)updatep(lc,l,mid,p,k1,k2);
else updatep(rc,mid+1,r,p,k1,k2);
pushup(u);
}
node query(int u,int l,int r,int st,int des){
if(st<=l&&r<=des)return s[u];
pushdown(u);
if(des<=mid)return query(lc,l,mid,st,des);
if(mid<st)return query(rc,mid+1,r,st,des);
return query(lc,l,mid,st,des)+query(rc,mid+1,r,st,des);
}
#undef lc
#undef rc
#undef mid
}
inline int pathupdate(int u,int v,int k){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
Seg::update(1,1,n,in[top[u]],in[u],k);
u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
if(u!=v)Seg::update(1,1,n,in[v]+1,in[u],k);
return v;
}
ll anc[N],lmx[N],prt[N],prs[N];
inline void pathquery(int u){
while(0721){
int tp=top[u],ff=fa[tp];
node now=Seg::query(1,1,n,in[tp],in[ed[tp]]);
ans.erase(anc[tp]);
anc[tp]=now.ans;
ans.push(anc[tp]);
if(!ff)break;
ll prmx=prt[ff],semx=prs[ff];
s[ff].erase(lmx[tp]);
lmx[tp]=now.lmx;
s[ff].push(lmx[tp]);
prt[ff]=s[ff].top(),prs[ff]=s[ff].setop();
Seg::updatep(1,1,n,in[ff],prt[ff]-prmx,prs[ff]-semx);
u=ff;
}
}
signed main(){
#ifdef Stargazer
freopen("lx.cpp","r",stdin);
#endif
n=read(),m=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
e[u].pb(v),e[v].pb(u);
}
dfs1(1),dfs2(1,1);
for(int i=1;i<=n;i++)s[i].push(0),ans.push(0);
for(int i=1;i<=m;i++){
char ch=readchar();
int u,v,w;
if(ch=='+'){
u=read(),v=read(),w=read();
pt[i].u=u,pt[i].v=v,pt[i].w=w;
}
else {
int tt=read();
u=pt[tt].u,v=pt[tt].v,w=-pt[tt].w;
}
int lca=pathupdate(u,v,w);//except lca
Seg::updatea(1,1,n,in[lca],w);
pathquery(u),pathquery(v);
cout<<ans.top()<<'\n';
}
return 0;
}