[Vani有约会] 雨天的尾巴
题意:
有一棵n个点的树,m次操作,每次操作给路径$(u,v)$上每个点发一个类型为w的物品。
在所有操作后请你求出每个点个数最多的物品类型。
$n,m,w\leq 10^{5}$。
题解:
两种做法,树链剖分和线段树合并。下一篇写线段树合并。
树链剖分基本就是把序列问题上树,于是考虑序列怎么做,直接把区间加改成差分再维护一棵权值线段树即可。
复杂度$O(n\log^{2}{n})$。注意那个w不一定小于n,这个玩意差点把我坑死。
套路:
- 树上路径相关问题:如果序列可做$\rightarrow$树剖上树。
代码:
#include<bits/stdc++.h> #define maxn 1000005 #define maxm 500005 #define inf 0x7fffffff #define ll long long #define rint register int #define debug(x) cerr<<#x<<": "<<x<<endl #define fgx cerr<<"--------------"<<endl #define dgx cerr<<"=============="<<endl using namespace std; int top[maxn],E[maxn],id[maxn],rt[maxn]; int to[maxn<<1],nxt[maxn<<1],hd[maxn],cnt; int F[maxn],dep[maxn],siz[maxn],son[maxn]; int tr[maxn<<2],mx[maxn<<2],ans[maxn]; vector<int> vc[maxn]; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline void addedge(int u,int v){ to[++cnt]=v,nxt[cnt]=hd[u],hd[u]=cnt; to[++cnt]=u,nxt[cnt]=hd[v],hd[v]=cnt; } inline void dfs1(int u,int fa){ F[u]=fa,dep[u]=dep[fa]+1,siz[u]=1; for(int i=hd[u];i;i=nxt[i]){ int v=to[i]; if(v==fa) continue; dfs1(v,u),siz[u]+=siz[v]; if(siz[v]>siz[son[u]]) son[u]=v; } } inline void dfs2(int u,int tp){ E[++E[0]]=u,id[u]=E[0],top[u]=tp; if(son[u]) dfs2(son[u],tp); for(int i=hd[u];i;i=nxt[i]){ int v=to[i]; if(v!=F[u] && v!=son[u]) dfs2(v,v); } } inline void solve(int u,int v,int w){ while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]]) swap(u,v); int st=id[top[u]],ed=id[u]; vc[st].push_back(w),vc[ed+1].push_back(-w); u=F[top[u]]; } if(dep[u]>dep[v]) swap(u,v); int st=id[u],ed=id[v]; vc[st].push_back(w),vc[ed+1].push_back(-w); } inline void add(int x,int y,int l,int r,int k){ if(l==r){tr[k]+=y;return;} int mid=l+r>>1; if(x<=mid) add(x,y,l,mid,k<<1); else add(x,y,mid+1,r,k<<1|1); if(tr[k<<1]>=tr[k<<1|1]) tr[k]=tr[k<<1],mx[k]=mx[k<<1]; else tr[k]=tr[k<<1|1],mx[k]=mx[k<<1|1]; } inline void build(int l,int r,int k){ if(l==r){mx[k]=l;return;} int mid=l+r>>1; build(l,mid,k<<1); build(mid+1,r,k<<1|1); } int main(){ int n=read(),m=read(); for(int i=1;i<n;i++){ int u=read(),v=read(); addedge(u,v); } dfs1(1,0),dfs2(1,1); for(int i=1;i<=m;i++){ int u=read(),v=read(),w=read(); solve(u,v,w); } build(1,100000,1); for(int i=1;i<=n;i++){ for(int j=0;j<vc[i].size();j++){ if(vc[i][j]>0) add(vc[i][j],1,1,100000,1); else add(-vc[i][j],-1,1,100000,1); } ans[E[i]]=(tr[1]==0)?0:mx[1]; } for(int i=1;i<=n;i++) cout<<ans[i]<<endl; return 0; }