题目描述
首先村落里的一共有 n 座房屋,并形成一个树状结构。然后救济粮分 m 次发放,每次选择两个房屋 (x, y),然后对于 x 到 y 的路径上(含 x 和 y)每座房子里发放一袋 z 类型的救济粮。
然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。
解题思路
可以在每个节点用值域线段树维护最多的是那种救济粮,对于修改操作,可以运用树上差分的思想,在x和y增添一,在lca和lca的父亲处减掉一,最后查询时自底向上用线段树合并维护前缀和就可以了
PS:还有一个小细节是题目要求数量相同返回编号最小的,所以在pushup时
void pushup(int k)
{
if(lson[k]==0)
{
Cnt[k]=Cnt[rson[k]];
Max[k]=Max[rson[k]];
return;
}
if(rson[k]==0)
{
Cnt[k]=Cnt[lson[k]];
Max[k]=Max[lson[k]];
return;
}
if(Cnt[lson[k]]>=Cnt[rson[k]])//一定要在这加上等号,因为是值域线段树,左儿子一定小于右儿子
{
Cnt[k]=Cnt[lson[k]];
Max[k]=Max[lson[k]];
return;
}
if(Cnt[lson[k]]<Cnt[rson[k]])
{
Cnt[k]=Cnt[rson[k]];
Max[k]=Max[rson[k]];
return;
}
}
完整代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
const int M = N*80;
const int R = 1e5+7;
struct node
{
int y,next;
}e[2*N];
int link[N],t,n,m,tot=0;
void Add(int x,int y)
{
t++;
e[t].y=y;
e[t].next=link[x];
link[x]=t;
}
int fa[N],dep[N],top[N],siz[N],son[N];
void dfs(int x,int pre)
{
fa[x]=pre;
siz[x]=1;
dep[x]=dep[pre]+1;
for(int i=link[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==pre) continue;
dfs(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]])
son[x]=y;
}
}
void Exdfs(int x,int topth)
{
top[x]=topth;
if(!son[x]) return;
Exdfs(son[x],topth);
for(int i=link[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==fa[x]||y==son[x]) continue;
Exdfs(y,y);
}
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
return x;
}
int Max[M],Cnt[M],lson[M],rson[M],rot[N];
inline int read()
{
int X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
if(flag) return X;
return ~(X-1);
}
void pushup(int k)
{
if(lson[k]==0)
{
Cnt[k]=Cnt[rson[k]];
Max[k]=Max[rson[k]];
return;
}
if(rson[k]==0)
{
Cnt[k]=Cnt[lson[k]];
Max[k]=Max[lson[k]];
return;
}
if(Cnt[lson[k]]>=Cnt[rson[k]])
{
Cnt[k]=Cnt[lson[k]];
Max[k]=Max[lson[k]];
return;
}
if(Cnt[lson[k]]<Cnt[rson[k]])
{
Cnt[k]=Cnt[rson[k]];
Max[k]=Max[rson[k]];
return;
}
}
void update(int &k,int l,int r,int x,int add)
{
if(!k) k=++tot;
if(l==r)
{
Max[k]=l;
Cnt[k]+=add;
return;
}
int mid=(l+r)>>1;
if(x<=mid) update(lson[k],l,mid,x,add);
else update(rson[k],mid+1,r,x,add);
pushup(k);
}
int ans[N];
void merge(int &x,int y,int l,int r,int root)
{
if(!x) x=++tot;
if(l==r)
{
Cnt[x]=Cnt[x]+Cnt[y];
Max[x]=l;
return;
}
int mid=(l+r)>>1;
if(lson[x]&&lson[y]) merge(lson[x],lson[y],l,mid,root);
else if(!lson[x]&&lson[y]) lson[x]=lson[y];
if(rson[x]&&rson[y]) merge(rson[x],rson[y],mid+1,r,root);
else if(!rson[x]&&rson[y]) rson[x]=rson[y];
pushup(x);
}
void Get(int x)
{
for(int i=link[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==fa[x]) continue;
Get(y);
merge(rot[x],rot[y],1,R,x);
}
ans[x]=Max[rot[x]];
if(Cnt[rot[x]]==0) ans[x]=0;
}
int main()
{
n=read();
m=read();
for(int i=1;i<n;i++)
{
int x,y;
x=read();
y=read();
Add(x,y);
Add(y,x);
}
dfs(1,0);
Exdfs(1,1);
while(m--)
{
int a,b,x;
a=read();
b=read();
x=read();
int lca=LCA(a,b);
update(rot[a],1,R,x,1);
update(rot[b],1,R,x,1);
update(rot[lca],1,R,x,-1);
update(rot[fa[lca]],1,R,x,-1);
}
Get(1);
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
return 0;
}