P4556 [Vani有约会]雨天的尾巴(线段树合并+lca)

P4556 [Vani有约会]雨天的尾巴

每个操作拆成4个进行树上差分,动态开点线段树维护每个点的操作。

离线处理完向上合并就好了

luogu倍增lca被卡了5分.....于是用rmq维护....

常数很大,被bzoj卡了(但是我不想改了)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define ri register int
using namespace std;
int read(){
    char c=getchar(); int x=0;
    while(c<'0'||c>'9') c=getchar();
    while('0'<=c&&c<='9') x=x*10+c-48,c=getchar();
    return x;
}
#define N 100001
#define W 5000005
int n,m,fa[N],fir[N],Log[N*2],f[18][N*2],tp,dfn[N],cc,ans[N];//一定记住st表的大小是n*2
int u,rt[N],lc[W],rc[W],mx[W],id[W];
vector <int> g[N];
#define mid (l+r)/2
void up(int o){
    mx[o]=id[o]=0;
    if(mx[lc[o]]>mx[o]) mx[o]=mx[lc[o]],id[o]=id[lc[o]];
    if(mx[rc[o]]>mx[o]) mx[o]=mx[rc[o]],id[o]=id[rc[o]];
}
void merge(int &o,int p,int l,int r){//线段树合并
    if(!o||!p){o=o+p; return;}
    if(l==r){mx[o]+=mx[p]; return;}
    merge(lc[o],lc[p],l,mid);
    merge(rc[o],rc[p],mid+1,r); up(o);
}
void ins(int &o,int l,int r,int k,int v){
    if(!o)o=++u;
    if(l==r){mx[o]+=v,id[o]=l; return;}
    if(k<=mid) ins(lc[o],l,mid,k,v);
    else ins(rc[o],mid+1,r,k,v);
    up(o);
}
void dfs(int x,int Fa){
    fa[x]=Fa; f[0][++tp]=dfn[++cc]=x; fir[x]=tp;
    for(int i=0;i<g[x].size();++i) if(g[x][i]!=Fa) dfs(g[x][i],x),f[0][++tp]=x;
}
inline int Min(int x,int y){return fir[x]<fir[y]?x:y;}
int lca(int x,int y){
    ri l=fir[x],r=fir[y]; if(l>r) swap(l,r);
    ri k=Log[r-l+1];
    return Min(f[k][l],f[k][r-(1<<k)+1]);
}
int main(){
    n=read(); m=read(); int u,v,w,p;
    for(ri i=1;i<n;++i){
        u=read(),v=read();
        g[u].push_back(v);
        g[v].push_back(u);
    }dfs(1,0); Log[0]=-1;
    for(ri i=1;i<=tp;++i) Log[i]=Log[i>>1]+1;
    for(ri i=1;i<=Log[tp];++i)
        for(ri j=1;j+(1<<i)-1<=tp;++j)
            f[i][j]=Min(f[i-1][j],f[i-1][j+(1<<(i-1))]);
    while(m--){
        u=read(),v=read(),w=read(); p=lca(u,v);
        ins(rt[u],1,N-1,w,1);
        ins(rt[v],1,N-1,w,1);
        ins(rt[p],1,N-1,w,-1);
        if(fa[p]) ins(rt[fa[p]],1,N-1,w,-1);//拆成4个操作
    }
    for(ri i=n;i;--i)
        p=dfn[i],ans[p]=id[rt[p]],merge(rt[fa[p]],rt[p],1,N-1);
    for(ri i=1;i<=n;++i) printf("%d\n",ans[i]);
    return 0;
}

 

转载于:https://www.cnblogs.com/kafuuchino/p/11551849.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值