每个操作拆成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 ",ans[i]); return 0; }