P3714 [BJOI2017]树的难题 题解
我太蒻了,又调了一天……
本题如果没有
现在我们加上了
如果在范围内进行
对于每一个点,分裂时按照其与子节点的边的颜色进行排序,然后在每次对于一个子树有
如果合并时边相同,要减去
所以要维护两个线段树,一个代表与自己颜色不同,一个代表与自己颜色相同
所以大概步骤是这样的:
1、处理每一棵子树的每个深度所得到答案最大值。
2、对所有子树按颜色进行排序。
3、枚举一棵子树的深度,利用线段树求得另一棵子树合法的长度能得到答案的最大值,如果颜色相等要减去根到子节点的颜色所代表的权值。
4、更新同种颜色的线段树。
5、若这个颜色枚举完了,将同种颜色的线段树归并到不同种颜色线段树上,并清空同种颜色线段树。
然后是点分治的最重要的,清空数组。
为方便清空,在进行排序时,会将同种颜色的按深度排序。
那么子树每个深度的最大答案就可以利用深度进行清空,而线段树归并时同样深度也是最后一个树的深度。
然后其他都不是特别难,除了线段树。
线段树建树来清空肯定会 T,所以在每个节点第一次更新后,维护一个栈或队列记录这个点,最后要清空时依次弹出即可。
时间复杂度:
#include<iostream>
#include<cstdio>
#include<stack>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
const int N=2e5+5;
int n,m,l,r,t[N],mp[N],siz[N],root;
int vis[N],tot,ans=-2000000000,dep[N],c[N],tmp[N],cnt,nl,nr,k,dis[N];
struct segmentree
{
int f[4*N];
stack<int>s;
inline int ls(int x)
{
return x<<1;
}
inline int rs(int x)
{
return x<<1|1;
}
inline void pushup(int x)
{
if(f[x]==-2000000000)s.push(x);
f[x]=max(f[ls(x)],f[rs(x)]);
}
void build(int x,int l,int r)
{
f[x]=-2000000000;
if(l==r)return;
int mid=(l+r)>>1;
build(ls(x),l,mid);
build(rs(x),mid+1,r);
pushup(x);
}
void update(int x,int l,int r)
{
if(l==r)
{
if(f[x]==-2000000000)s.push(x);
f[x]=max(f[x],k);
return;
}
int mid=(l+r)>>1;
if(mid>=nl)update(ls(x),l,mid);
else update(rs(x),mid+1,r);
pushup(x);
}
int search(int x,int l,int r)
{
if(l>=nl&&r<=nr)return f[x];
int mid=(l+r)>>1,num=-2000000000;
if(mid>=nl)num=max(num,search(ls(x),l,mid));
if(mid<nr)num=max(num,search(rs(x),mid+1,r));
return num;
}
void clear()
{
while(!s.empty())
{
f[s.top()]=-2000000000;
s.pop();
}
}
}t1,t2;
struct node
{
int to,data;
};
vector<node>a[N];
int cmp(int x,int y)
{
if(c[x]==c[y])return dep[x]<dep[y];
return c[x]<c[y];
}
void findzx(int x,int fa)
{
mp[x]=0;
siz[x]=1;
int len=a[x].size();
for(int i=0;i<len;i++)
{
if(vis[a[x][i].to]||a[x][i].to==fa)continue;
findzx(a[x][i].to,x);
siz[x]+=siz[a[x][i].to];
mp[x]=max(mp[x],siz[a[x][i].to]);
}
mp[x]=max(mp[x],tot-siz[x]);
if(mp[x]<mp[root])root=x;
}
void dfs(int x,int fa)
{
int len=a[x].size();
dep[x]=1;
for(int i=0;i<len;i++)
{
if(vis[a[x][i].to]||a[x][i].to==fa)continue;
dfs(a[x][i].to,x);
dep[x]=max(dep[x],dep[a[x][i].to]+1);
}
}
void getdis(int x,int fa,int num,int deep,int sum)
{
dis[deep]=max(dis[deep],sum);
int len=a[x].size();
for(int i=0;i<len;i++)
{
if(a[x][i].to==fa||vis[a[x][i].to])continue;
int lim=sum;
if(a[x][i].data!=num)lim+=t[a[x][i].data];
getdis(a[x][i].to,x,a[x][i].data,deep+1,lim);
}
}
void clac(int x)
{
int len=a[x].size();
cnt=0;
for(int i=0;i<len;i++)
{
if(vis[a[x][i].to])continue;
c[a[x][i].to]=a[x][i].data;
dfs(a[x][i].to,x);
tmp[++cnt]=a[x][i].to;
}
sort(tmp+1,tmp+1+cnt,cmp);
for(int i=1;i<=cnt;i++)
{
dis[1]=t[c[tmp[i]]];
getdis(tmp[i],x,c[tmp[i]],1,dis[1]);
for(int j=1;j<=dep[tmp[i]];j++)
{
if(j>=l&&j<=r)ans=max(ans,dis[j]);
nl=l-j,nr=r-j;
if(nl<=0)nl=1;
int num1=-2000000000,num2=-2000000000;
if(nl<=nr)num1=t1.search(1,1,n);
if(nl<=nr)num2=t2.search(1,1,n);
ans=max(ans,max(num1+dis[j],num2+dis[j]-t[c[tmp[i]]]));
}
for(int j=1;j<=dep[tmp[i]];j++)
{
nl=j,k=dis[j];
t2.update(1,1,n);
dis[j]=-2000000000;
}
if(i!=cnt&&c[tmp[i]]!=c[tmp[i+1]])
{
for(int j=1;j<=dep[tmp[i]];j++)
{
nl=j,nr=j;
k=t2.search(1,1,n);
t1.update(1,1,n);
}
t2.clear();
}
}
t1.clear();
t2.clear();
}
void divide(int x,int num)
{
vis[x]=1;
clac(x);
int len=a[x].size();
for(int i=0;i<len;i++)
{
if(vis[a[x][i].to])continue;
if(siz[x]>siz[a[x][i].to])tot=siz[a[x][i].to];
else tot=num-siz[x];
root=0;
findzx(a[x][i].to,x);
divide(root,tot);
}
}
int main()
{
//freopen("journey1.in","r",stdin);
scanf("%d%d%d%d",&n,&m,&l,&r);
for(int i=1;i<=m;i++)scanf("%d",&t[i]);
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
a[u].push_back({v,w});
a[v].push_back({u,w});
}
tot=n;
mp[0]=2e9;
t1.build(1,1,n);
t2.build(1,1,n);
findzx(1,0);
for(int i=1;i<=n;i++)dis[i]=-2000000000;
divide(root,n);
printf("%d",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话