JZOJ 3397. 【GDOI2014模拟】雨天的尾巴【线段树】


题目:

传送门


题意:

在一个村子中,有些房子互相连通,并使得整个村子成为了一个树形结构
现在会有 m m m次发放救济粮的机会, ( u , v , z ) (u,v,z) (u,v,z)表示由 u u u v v v一整条路径上都加上一次 z z z种的粮食
问我们每个房子存放数量最多的粮食是哪个品种


分析:

我们可以通过差分来表示一段房子的增值,在 u , v u,v u,v打上 + 1 +1 +1,在它们的 L C A LCA LCA L C A LCA LCA的父亲打上 − 1 -1 1
接着我们用线段树合并进行 l o g log log的求解


代码:

#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define LL long long 
#define LZX WCIMU
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
} 
int n,m,top,ls[200005],ans[100005];
struct mona {int next,to;} s[200005];
struct joker {int next,to,op;};
void Insert(int x,int y) {s[++top]=(mona){ls[x],y},ls[x]=top; }
struct SeqTree
{
     int cnt,lson[4000005],rson[4000005],Max[4000005],id[4000005],rt[100005],rab[4000005],tot,top,ls[100005]; joker s[400005]; 
     void Insert(int x,int y,int op) { s[++top]=(joker) {ls[x],y,op},ls[x]=top; }
     int New() {if(tot) return rab[tot--]; return ++cnt; }
     void Throw(int x) {rab[++top]=x,lson[x]=rson[x]=Max[x]=id[x]=0; }
     void Pushup(int x)
	 {
        if(Max[lson[x]]>=Max[rson[x]]) Max[x]=Max[lson[x]],id[x]=id[lson[x]];
        else Max[x]=Max[rson[x]],id[x]=id[rson[x]];
     }
     void Modify(int l,int r,int &x,int pos,int val)
	 {
        if(!x) x=New(); if(l==r) {Max[x]+=val,id[x]=l;}
        else
		{
			int mid=l+r>>1;
	        if(pos<=mid) Modify(l,mid,lson[x],pos,val);
	        else Modify(mid+1,r,rson[x],pos,val);
	        Pushup(x);
		} 
		if(!Max[x]) id[x]=0;
     }
     int Merge(int l,int r,int u,int v)
	 {
        if(!u||!v) return u|v;
        int now=New(),mid=l+r>>1; if(l==r) Max[now]=Max[u]+Max[v],id[now]=l;
        else lson[now]=Merge(l,mid,lson[u],lson[v]),rson[now]=Merge(mid+1,r,rson[u],rson[v]),Pushup(now);
        Throw(u);Throw(v); 
		return now;
    }
}T;
struct Tree
{
    int top[100005],son[100005],siz[100005],fa[100005],dep[100005];
     void dfs(int k,int Fa)
	 {
        fa[k]=Fa,siz[k]=1,dep[k]=dep[Fa]+1;
        for(int i=ls[k];i;i=s[i].next)
		{
            int to=s[i].to; if(to==Fa) continue;
            dfs(to,k),siz[k]+=siz[to];
            if(siz[son[k]]<siz[to]) son[k]=to;
        }   return ;
    }
     void dfs2(int k,int to)
	 {
        top[k]=to; if(son[k]) dfs2(son[k],to);
        for(int i=ls[k];i;i=s[i].next)
		{
            int to=s[i].to; if(to==fa[k]||to==son[k]) continue;
            dfs2(to,to);
        }
    }
     int lca(int u,int v)
	 {
        while(top[u]!=top[v])
		{
            if(dep[top[u]]<dep[top[v]]) swap(u,v);
            u=fa[top[u]];
        }  
	    return dep[u]<dep[v]?u:v;
    }
}S;
void dfs(int k,int fa)
{
    for(int i=ls[k];i;i=s[i].next) if(s[i].to!=fa) dfs(s[i].to,k);
    for(int i=T.ls[k];i;i=T.s[i].next) T.Modify(1,100000,T.rt[k],T.s[i].to,T.s[i].op);
    ans[k]=T.id[T.rt[k]];
    if(S.fa[k]) T.rt[S.fa[k]]=T.Merge(1,100000,T.rt[S.fa[k]],T.rt[k]);
    return ;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<n;++i)
	{
        int x=read(),y=read();
        Insert(x,y),Insert(y,x);
    }   
	S.dfs(1,0);S.dfs2(1,1);
    for(int i=1;i<=m;++i)
	{
        int u=read(),v=read(),val=read();
        int lca=S.lca(u,v),Flca=S.fa[lca];
        T.Insert(u,val,1);T.Insert(v,val,1);T.Insert(lca,val,-1);T.Insert(Flca,val,-1);
    }   
	dfs(1,0); 
	for(int i=1;i<=n;++i) printf("%d\n",ans[i]);
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值