版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ccsu_cat/article/details/84036613
题意:给一棵树,每个节点有一个编号,求每颗子树最多编号的和。
线段树合并模板题
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
vector<int>G[maxn];
int mx[maxn*20],rt[maxn*20],ls[maxn*20],rs[maxn*20],V[maxn],n,cnt=0;
ll ans[maxn],sum[maxn*20];
void pushup(int o)
{
mx[o]=max(mx[ls[o]],mx[rs[o]]);
if(mx[ls[o]]==mx[rs[o]])sum[o]=sum[ls[o]]+sum[rs[o]];
else
{
if(mx[ls[o]]>mx[rs[o]])sum[o]=sum[ls[o]];
else sum[o]=sum[rs[o]];
}
}
int merge(int a,int b,int l,int r)
{
if(!a||!b)return a|b;
if(l==r)
{
sum[a]=l;
mx[a]+=mx[b];
return a;
}
int m=(l+r)/2;
if(ls[a]||ls[b])ls[a]=merge(ls[a],ls[b],l,m);
if(rs[a]||rs[b])rs[a]=merge(rs[a],rs[b],m+1,r);
pushup(a);
return a;
}
void up(int &o,int l,int r,int k)
{
if(!o)o=++cnt;
if(l==r)
{
mx[o]++;
sum[o]=l;
return;
}
int m=(l+r)/2;
if(k<=m)up(ls[o],l,m,k);
else up(rs[o],m+1,r,k);
pushup(o);
}
void dfs(int u,int fa)
{
for(int i=0;i<G[u].size();i++)
{
if(G[u][i]==fa)continue;
dfs(G[u][i],u);
merge(rt[u],rt[G[u][i]],1,n);
}
up(rt[u],1,n,V[u]);
ans[u]=sum[rt[u]];
}
int main()
{
int u,v;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&V[i]),rt[i]=++cnt;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0);
for(int i=1;i<n;i++)printf("%I64d ",ans[i]);
printf("%I64d\n",ans[n]);
}
看了一些这题关于启发式合并的题解,也需要重链剖分,按照网上大神的代码仿写了一遍,假装自己学懂了启发式合并.....
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
vector<int>G[maxn];
int son[maxn],size[maxn],a[maxn],f[maxn],vis[maxn],cnt[maxn],mx=0;
ll sum=0,ans[maxn];
void dfs(int u,int fa)
{
f[u]=fa;
size[u]=1;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v==fa)continue;
dfs(v,u);
size[u]+=size[v];
if(size[v]>size[son[u]])son[u]=v;
}
}
void cal(int u,int v)
{
cnt[a[u]]+=v;
if(cnt[a[u]]==mx)sum+=a[u];
else if(cnt[a[u]]>mx)sum=a[u],mx=cnt[a[u]];
for(int i=0;i<G[u].size();i++)
if(G[u][i]!=f[u]&&!vis[G[u][i]])
cal(G[u][i],v);
}
void dfs2(int u)
{
for(int i=0;i<G[u].size();i++)
if(G[u][i]!=f[u]&&G[u][i]!=son[u])dfs2(G[u][i]);
if(son[u])dfs2(son[u]),vis[son[u]]=1;
cal(u,1);
ans[u]=sum;
if(son[u])vis[son[u]]=0;
if(son[f[u]]!=u)cal(u,-1),sum=0,mx=0;
}
int main()
{
int n,u,v;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0);
dfs2(1);
for(int i=1;i<n;i++)printf("%I64d ",ans[i]);
printf("%I64d\n",ans[n]);
}