月下毛景树
思路
树链剖分裸题,但是维护的是边权,考虑到每个节点仅有一个父亲,因此用节点来维护与它父亲相连的那条边的边权。
第一种操作,记录下每条边深度最深的端点,单点修改即可;
第二种操作,沿着重链区间覆盖;
第三种操作,沿着重链区间加;
第四种操作,沿着重链查区间最大值。
用线段树来维护这些信息即可。另外要注意两点的lca是不参与路径上的修改的,因此每次修改时要保证lca的点权不变。
代码
#include<bits/stdc++.h>
#define lc p<<1
#define rc p<<1|1
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define en puts("")
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll>
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void OP() {}
void op() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
int __=0;
_=0;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
__=1;
ch=getchar();
}
while(isdigit(ch))
{
_=_*10+ch-48;
ch=getchar();
}
_=__?-_:_;
read(oth...);
}
template <typename T>
void Out(T _)
{
if(_<0)
{
putchar('-');
_=-_;
}
if(_>=10)
Out(_/10);
putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void OP(T _, T2... oth)
{
Out(_);
putchar('\n');
OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
Out(_);
putchar(' ');
op(oth...);
}
/*#################################*/
const ll N=1E5+10;
ll n,tot,timer;
ll siz[N],father[N],dep[N],head[N],son[N],dfsn[N],top[N],maxi[4*N],tag[4*N],fg[4*N];
struct edge{
ll u,v,w;
}edge[N];
struct Edge{
ll nxt,to,w;
}e[2*N];
void add_edge(ll u,ll v,ll w,int flag)
{
e[++tot]=(Edge){head[u],v,w};
head[u]=tot;
if(flag)
add_edge(v,u,w,0);
}
void dfs(ll u,ll fa)
{
siz[u]=1;
father[u]=fa;
dep[u]=dep[fa]+1;
bl(u,i)
{
ll v=e[i].to;
if(v==fa)
continue;
dfs(v,u);
if(siz[v]>siz[son[u]])
son[u]=v;
siz[u]+=siz[v];
}
}
void dfs_(ll u,ll tp)
{
dfsn[u]=++timer;
top[u]=tp;
if(!son[u])
return;
dfs_(son[u],tp);
bl(u,i)
{
ll v=e[i].to;
if(v==father[u] || v==son[u])
continue;
dfs_(v,v);
}
}
ll lca(ll u,ll v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
u=father[top[u]];
}
return dep[u]<=dep[v]?u:v;
}
void update(ll p)
{
maxi[p]=max(maxi[lc],maxi[rc]);
}
void flag(ll p,ll add_val,ll cover_val)
{
if(cover_val!=-1)
{
maxi[p]=fg[p]=cover_val;
tag[p]=0;
}
if(add_val)
{
maxi[p]+=add_val;
tag[p]+=add_val;
}
}
void push_down(ll p)
{
flag(lc,tag[p],fg[p]);
flag(rc,tag[p],fg[p]);
tag[p]=0;
fg[p]=-1;
}
void modify(ll p,ll l,ll r,ll al,ll ar,ll val)
{
if(al<=l && ar>=r)
{
maxi[p]+=val;
tag[p]+=val;
return;
}
ll mid=(l+r)>>1;
push_down(p);
if(al<=mid)
modify(lc,l,mid,al,ar,val);
if(ar>mid)
modify(rc,mid+1,r,al,ar,val);
update(p);
}
void cover(ll p,ll l,ll r,ll al,ll ar,ll val)
{
if(al<=l && ar>=r)
{
maxi[p]=fg[p]=val;
tag[p]=0;
return;
}
push_down(p);
ll mid=(l+r)>>1;
if(al<=mid)
cover(lc,l,mid,al,ar,val);
if(ar>mid)
cover(rc,mid+1,r,al,ar,val);
update(p);
}
ll query(ll p,ll l,ll r,ll al,ll ar)
{
if(al<=l && ar>=r)
return maxi[p];
ll mid=(l+r)>>1,ret=0;
push_down(p);
if(al<=mid)
ret=max(ret,query(lc,l,mid,al,ar));
if(ar>mid)
ret=max(ret,query(rc,mid+1,r,al,ar));
return ret;
}
void print()
{
rep(i,1,7)
{
op(maxi[i],tag[i],fg[i]);
en;
}
en;
}
int main()
{
read(n);
ll u,v,w;
memset(fg,-1,sizeof(fg));
rep(i,1,n-1)
{
read(edge[i].u,edge[i].v,edge[i].w);
add_edge(edge[i].u,edge[i].v,0,1);
}
dfs(1,0);
dfs_(1,1);
rep(i,1,n-1)
{
ll &u=edge[i].u,&v=edge[i].v;
if(dep[u]<dep[v])
swap(u,v);
modify(1,1,n,dfsn[u],dfsn[u],edge[i].w);
}
string s;
while(cin>>s)
{
if(s=="Stop")
break;
read(u,v);
if(s=="Change")
{
u=edge[u].u;
cover(1,1,n,dfsn[u],dfsn[u],v);
}
else if(s=="Cover")
{
read(w);
ll p=lca(u,v),tmp=query(1,1,n,dfsn[p],dfsn[p]);
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
cover(1,1,n,dfsn[top[u]],dfsn[u],w);
u=father[top[u]];
}
if(dep[u]>dep[v])
swap(u,v);
cover(1,1,n,dfsn[u],dfsn[v],w);
cover(1,1,n,dfsn[p],dfsn[p],tmp);
}
else if(s=="Add")
{
read(w);
ll p=lca(u,v);
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
modify(1,1,n,dfsn[top[u]],dfsn[u],w);
u=father[top[u]];
}
if(dep[u]>dep[v])
swap(u,v);
modify(1,1,n,dfsn[u],dfsn[v],w);
modify(1,1,n,dfsn[p],dfsn[p],-w);
}
else if(s=="Max")
{
ll p=lca(u,v),tmp=query(1,1,n,dfsn[p],dfsn[p]),ans=0;
cover(1,1,n,dfsn[p],dfsn[p],0);
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
ans=max(ans,query(1,1,n,dfsn[top[u]],dfsn[u]));
u=father[top[u]];
}
if(dep[u]>dep[v])
swap(u,v);
ans=max(ans,query(1,1,n,dfsn[u],dfsn[v]));
OP(ans);
modify(1,1,n,dfsn[p],dfsn[p],tmp);
}
}
}
Disruption P
思路
考虑每一条额外的边,添加这条边之后,就可以删去其两个端点间在原树路径上的任意一条边,因此可以用这条额外边的权值去更新这条路径上所有边的答案,用树链剖分维护一下即可。
还有一种更妙的做法,权值小的额外边更新路径上的答案后,这些答案就不需要再被更新了,因此像并查集那样维护一下每个原树上已经被更新过的边,直接往上跳就行。
树链剖分代码
#include<bits/stdc++.h>
#define lc p<<1
#define rc p<<1|1
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define en puts("")
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll>
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void OP() {}
void op() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
int __=0;
_=0;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
__=1;
ch=getchar();
}
while(isdigit(ch))
{
_=_*10+ch-48;
ch=getchar();
}
_=__?-_:_;
read(oth...);
}
template <typename T>
void Out(T _)
{
if(_<0)
{
putchar('-');
_=-_;
}
if(_>=10)
Out(_/10);
putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void OP(T _, T2... oth)
{
Out(_);
putchar('\n');
OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
Out(_);
putchar(' ');
op(oth...);
}
/*#################################*/
const ll N=5E4+10;
ll n,m,tot,timer;
ll head[N],dep[N],siz[N],father[N],top[N],dfsn[N],son[N],mini[4*N],tag[4*N];
struct edge{
ll u,v;
}edge[N];
struct Edge{
ll nxt,to,w;
}e[N<<1];
void add_edge(ll u,ll v,ll w,int flag)
{
e[++tot]=(Edge){head[u],v,w};
head[u]=tot;
if(flag)
add_edge(v,u,w,0);
}
void dfs(ll u,ll fa)
{
dep[u]=dep[fa]+1;
siz[u]=1;
father[u]=fa;
bl(u,i)
{
ll v=e[i].to;
if(v==fa)
continue;
dfs(v,u);
if(siz[v]>siz[son[u]])
son[u]=v;
siz[u]+=siz[v];
}
}
void dfs_(ll u,ll tp)
{
top[u]=tp;
dfsn[u]=++timer;
if(!son[u])
return;
dfs_(son[u],tp);
bl(u,i)
{
ll v=e[i].to;
if(v==son[u] || v==father[u])
continue;
dfs_(v,v);
}
}
void update(ll p)
{
mini[p]=min(mini[lc],mini[rc]);
}
void push_down(ll p)
{
tag[lc]=min(tag[lc],tag[p]);
tag[rc]=min(tag[rc],tag[p]);
mini[lc]=min(mini[lc],tag[p]);
mini[rc]=min(mini[rc],tag[p]);
tag[p]=LLM;
}
void cover(ll p,ll l,ll r,ll al,ll ar,ll val,ll ty)
{
if(al<=l && ar>=r)
{
if(ty)
{
mini[p]=val;
return;
}
mini[p]=min(mini[p],val);
tag[p]=min(tag[p],val);
return;
}
ll mid=(l+r)>>1;
push_down(p);
if(al<=mid)
cover(lc,l,mid,al,ar,val,ty);
if(ar>mid)
cover(rc,mid+1,r,al,ar,val,ty);
update(p);
}
ll query(ll p,ll l,ll r,ll al,ll ar)
{
if(al<=l && ar>=r)
return mini[p];
ll mid=(l+r)>>1,ret=LLM;
push_down(p);
if(al<=mid)
ret=query(lc,l,mid,al,ar);
if(ar>mid)
ret=min(ret,query(rc,mid+1,r,al,ar));
return ret;
}
ll lca(ll u,ll v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
u=father[top[u]];
}
return dep[u]<dep[v]?u:v;
}
int main()
{
read(n,m);
rep(i,1,n-1)
{
read(edge[i].u,edge[i].v);
add_edge(edge[i].u,edge[i].v,0,1);
}
dfs(1,0);
dfs_(1,1);
rep(i,1,4*n)
mini[i]=tag[i]=LLM;
ll u,v,w;
rep(i,1,m)
{
read(u,v,w);
ll p=lca(u,v),tmp=query(1,1,n,dfsn[p],dfsn[p]);
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
cover(1,1,n,dfsn[top[u]],dfsn[u],w,0);
u=father[top[u]];
}
if(dep[u]>dep[v])
swap(u,v);
cover(1,1,n,dfsn[u],dfsn[v],w,0);
cover(1,1,n,dfsn[p],dfsn[p],tmp,1);
}
rep(i,1,n-1)
{
if(dep[edge[i].u]<dep[edge[i].v])
swap(edge[i].u,edge[i].v);
ll res=query(1,1,n,dfsn[edge[i].u],dfsn[edge[i].u]);
if(res==LLM)
res=-1;
OP(res);
}
}
并查集代码
#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define en puts("")
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll>
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void OP() {}
void op() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
int __=0;
_=0;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
__=1;
ch=getchar();
}
while(isdigit(ch))
{
_=_*10+ch-48;
ch=getchar();
}
_=__?-_:_;
read(oth...);
}
template <typename T>
void Out(T _)
{
if(_<0)
{
putchar('-');
_=-_;
}
if(_>=10)
Out(_/10);
putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void OP(T _, T2... oth)
{
Out(_);
putchar('\n');
OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
Out(_);
putchar(' ');
op(oth...);
}
/*#################################*/
const ll N=5E4+10;
ll n,m,tot;
ll dep[N],f[N][20],fa[N],ans[N],head[N];
struct edge
{
ll u,v,w;
}medge[N],eedge[N];
struct Edge{
ll nxt,to,w;
}e[2*N];
void add_edge(ll u,ll v,ll w,int flag)
{
e[++tot]=(Edge){head[u],v,w};
head[u]=tot;
if(flag)
add_edge(v,u,w,0);
}
void dfs(ll u,ll fa)
{
dep[u]=dep[fa]+1;
rep(i,0,18)
f[u][i+1]=f[f[u][i]][i];
bl(u,i)
{
ll v=e[i].to;
if(v==fa)
continue;
f[v][0]=u;
dfs(v,u);
}
}
ll lca(ll u,ll v)
{
if(dep[u]<dep[v])
swap(u,v);
for(int i=18;i>=0;--i)
{
if(dep[f[u][i]]>=dep[v])
u=f[u][i];
if(u==v)
return v;
}
for(int i=18;i>=0;--i)
{
if(f[u][i]!=f[v][i])
{
u=f[u][i];
v=f[v][i];
}
}
return f[u][0];
}
ll find(ll x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int main()
{
read(n,m);
rep(i,1,n)
fa[i]=i;
ll u,v,w;
rep(i,1,n-1)
{
read(u,v);
add_edge(u,v,0,1);
eedge[i]=(edge){u,v};
}
rep(i,1,m)
{
read(u,v,w);
medge[i]=(edge){u,v,w};
}
sort(medge+1,medge+m+1,[](const edge &u,const edge &v)
{
return u.w<v.w;
});
memset(ans,-1,sizeof(ans));
dfs(1,0);
rep(i,1,n)
{
ll &u=eedge[i].u,&v=eedge[i].v;
if(dep[u]<dep[v])
swap(u,v);
}
rep(i,1,m)
{
ll u=medge[i].u,v=medge[i].v,w=medge[i].w,p=lca(u,v);
while(dep[u]>dep[p])
{
ll fu=find(u);
if(fu!=u)
u=fu;
else
{
ans[u]=w;
fa[u]=f[u][0];
u=f[u][0];
}
}
while(dep[v]>dep[p])
{
ll fv=find(v);
if(fv!=v)
v=fv;
else
{
ans[v]=w;
fa[v]=f[v][0];
v=f[v][0];
}
}
}
rep(i,1,n-1)
{
OP(ans[eedge[i].u]);
}
}
I love tree
思路
难度在于维护区间加平方,区间内每个位置加的数都各不相同。因此要找出它们的共同点。考虑对从左到右加递增的数字,位置加了,那么下标为的位置就加了。设,则原式可以写成。因为是一直不变的,因此只维护这个区间被加了多少次,的总和以及的总和即可,单点询问时直接加上该点值的贡献。
代码
#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define en puts("")
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll>
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void OP() {}
void op() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
int __=0;
_=0;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
__=1;
ch=getchar();
}
while(isdigit(ch))
{
_=_*10+ch-48;
ch=getchar();
}
_=__?-_:_;
read(oth...);
}
template <typename T>
void Out(T _)
{
if(_<0)
{
putchar('-');
_=-_;
}
if(_>=10)
Out(_/10);
putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void OP(T _, T2... oth)
{
Out(_);
putchar('\n');
OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
Out(_);
putchar(' ');
op(oth...);
}
/*#################################*/
const ll N=1E5+10;
ll n,q,tot,timer;
ll head[N],dfsn[N],dep[N],son[N],father[N],siz[N],top[N];
struct Edge{
ll nxt,to,w;
}e[2*N];
void add_edge(ll u,ll v,ll w,int flag)
{
e[++tot]=(Edge){head[u],v,w};
head[u]=tot;
if(flag)
add_edge(v,u,w,0);
}
struct BIT
{
ll t[N];
void add(ll x,ll val)
{
while(x<=n)
{
t[x]+=val;
x+=x&-x;
}
}
ll query(ll x)
{
ll ret=0;
while(x)
{
ret+=t[x];
x-=x&-x;
}
return ret;
}
void modify(ll L,ll R,ll val)
{
add(L,val);
add(R+1,-val);
}
}T1,T2,T3;
ll lca(ll u,ll v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
u=father[top[u]];
}
return dep[u]>dep[v]?v:u;
}
ll dis(ll u,ll v)
{
ll p=lca(u,v);
return dep[u]+dep[v]-2*dep[p];
}
void dfs(ll u,ll fa)
{
dep[u]=dep[fa]+1;
siz[u]=1;
father[u]=fa;
bl(u,i)
{
ll v=e[i].to;
if(v==fa)
continue;
dfs(v,u);
if(siz[v]>siz[son[u]])
son[u]=v;
siz[u]+=siz[v];
}
}
void dfs_(ll u,ll tp)
{
top[u]=tp;
dfsn[u]=++timer;
if(!son[u])
return;
dfs_(son[u],tp);
bl(u,i)
{
ll v=e[i].to;
if(v==son[u] || v==father[u])
continue;
dfs_(v,v);
}
}
ll gg(ll u)
{
ll du=dfsn[u];
return T1.query(du)+T2.query(du)*du*du-T3.query(du)*du;
}
int main()
{
read(n);
ll ty,u,v;
rep(i,1,n-1)
{
read(u,v);
add_edge(u,v,0,1);
}
dfs(1,0);
dfs_(1,1);
read(q);
while(q--)
{
read(ty);
if(ty==1)
{
read(u,v);
ll st=u,p=lca(u,v),midis=dis(u,p);
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
ll val=dis(st,top[u])+1;
ll tmp=dfsn[top[u]]-val;
if(dis(u,st)<midis)
tmp=dfsn[top[u]]+val;
T1.modify(dfsn[top[u]],dfsn[u],tmp*tmp);
T2.modify(dfsn[top[u]],dfsn[u],1);
T3.modify(dfsn[top[u]],dfsn[u],2*tmp);
u=father[top[u]];
}
if(dep[u]>dep[v])
swap(u,v);
ll val=dis(st,u)+1;
ll tmp=dfsn[u]-val;
if(dis(v,st)<midis)
tmp=dfsn[u]+val;
T1.modify(dfsn[u],dfsn[v],tmp*tmp);
T2.modify(dfsn[u],dfsn[v],1);
T3.modify(dfsn[u],dfsn[v],2*tmp);
// op(T1.query(2),T2.query(2),T3.query(2),gg(2));
// en;
}
else
{
read(u);
OP(gg(u));
}
}
}