【BZOJ3307】雨天的尾巴-线段树合并+树上差分
2018-03-13 19:58
375 查看
测试地址:雨天的尾巴
题目大意:一棵树,对其执行若干次操作,每次选定一条路径和一种型号的货物,然后给这条路径上所有的点派发一份选定型号的货物,最后求每个点获得的最多的货物的型号。
做法:本题需要用到线段树合并+树上差分。
首先,对一条路径派发货物,我们可以用树上差分的思想,将其转化为向路径的两个端点派发一份货物,然后向LCA和LCA的父亲派发负一份货物,那么每个点的货物相当于其子树中所有货物的和。要维护所有货物出现次数的最大值显然可以用线段树,那么我们就先按照操作对每一个点维护线段树,然后自底向上合并出每棵子树的线段树即可,复杂度应该在O(nlogn)O(nlogn)到O(nlog2n)O(nlog2n)之间,具体本人也不太会证明……
注意货物的序号可能很大,离散化一下就可以了。
以下是本人代码:
题目大意:一棵树,对其执行若干次操作,每次选定一条路径和一种型号的货物,然后给这条路径上所有的点派发一份选定型号的货物,最后求每个点获得的最多的货物的型号。
做法:本题需要用到线段树合并+树上差分。
首先,对一条路径派发货物,我们可以用树上差分的思想,将其转化为向路径的两个端点派发一份货物,然后向LCA和LCA的父亲派发负一份货物,那么每个点的货物相当于其子树中所有货物的和。要维护所有货物出现次数的最大值显然可以用线段树,那么我们就先按照操作对每一个点维护线段树,然后自底向上合并出每棵子树的线段树即可,复杂度应该在O(nlogn)O(nlogn)到O(nlog2n)O(nlog2n)之间,具体本人也不太会证明……
注意货物的序号可能很大,离散化一下就可以了。
以下是本人代码:
#include <bits/stdc++.h> #define inf 1000000000 using namespace std; int n,m,x[100010],y[100010],z[100010],fa[100010][21],dep[100010],rt[100010]={0},q[100010]; int first[100010]={0},tot=0,totp=0,mx[5000010],mxp[5000010],ch[5000010][2],ans[100010]; struct forsort { int id,val; }f[100010]; struct edge { int v,next; }e[200010]; void insert(int a,int b) { e[++tot].v=b,e[tot].next=first[a],first[a]=tot; } bool cmp(forsort a,forsort b) { return a.val<b.val; } void dfs(int v) { for(int i=first[v];i;i=e[i].next) if (e[i].v!=fa[v][0]) { fa[e[i].v][0]=v; dep[e[i].v]=dep[v]+1; dfs(e[i].v); } } int lca(int x,int y) { if (dep[x]<dep[y]) swap(x,y); for(int i=20;i>=0;i--) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i]; if (x==y) return x; for(int i=20;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } void pushup(int x) { if (!ch[x][0]) {mx[x]=mx[ch[x][1]],mxp[x]=mxp[ch[x][1]];return;} if (!ch[x][1]) {mx[x]=mx[ch[x][0]],mxp[x]=mxp[ch[x][0]];return;} mx[x]=max(mx[ch[x][0]],mx[ch[x][1]]); if (mx[ch[x][0]]>mx[ch[x][1]]) mxp[x]=mxp[ch[x][0]]; else if (mx[ch[x][0]]<mx[ch[x][1]]) mxp[x]=mxp[ch[x][1]]; else mxp[x]=min(mxp[ch[x][0]],mxp[ch[x][1]]); } void treeinsert(int &v,int l,int r,int x,int add) { if (!v) v=++totp,mx[v]=-inf,mxp[v]=ch[v][0]=ch[v][1]=0; if (l==r) { if (mx[v]==-inf) mx[v]=0; mx[v]+=add,mxp[v]=x; return; } int mid=(l+r)>>1; if (x<=mid) treeinsert(ch[v][0],l,mid,x,add); else treeinsert(ch[v][1],mid+1,r,x,add); pushup(v); } void merge_leaf(int x,int y) { mx[x]+=mx[y]; } void merge(int &x,int y) { if (!x) {x=y;return;} if (!y) return; merge(ch[x][0],ch[y][0]); merge(ch[x][1],ch[y][1]); if (!ch[x][0]&&!ch[x][1]) merge_leaf(x,y); else pushup(x); } void solve(int v) { for(int i=first[v];i;i=e[i].next) if (e[i].v!=fa[v][0]) { solve(e[i].v); merge(rt[v],rt[e[i].v]); } if (mx[rt[v]]>0) ans[v]=q[mxp[rt[v]]]; else ans[v]=0; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { int a,b; scanf("%d%d",&a,&b); insert(a,b),insert(b,a); } fa[1][0]=fa[0][0]=0;dep[1]=0,dep[0]=-1; dfs(1); for(int i=1;i<=20;i++) for(int j=1;j<=n;j++) fa[j][i]=fa[fa[j][i-1]][i-1]; for(int i=1;i<=m;i++) { scanf("%d%d%d",&x[i],&y[i],&z[i]); f[i].id=i,f[i].val=z[i]; } sort(f+1,f+m+1,cmp); tot=0; for(int i=1;i<=m;i++) { if (i==1||f[i].val!=f[i-1].val) q[++tot]=f[i].val; z[f[i].id]=tot; } for(int i=1;i<=m;i++) { int g=lca(x[i],y[i]); treeinsert(rt[x[i]],1,tot,z[i],1); treeinsert(rt[y[i]],1,tot,z[i],1); treeinsert(rt[g],1,tot,z[i],-1); if (g!=1) treeinsert(rt[fa[g][0]],1,tot,z[i],-1); } solve(1); for(int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; }
相关文章推荐
- BZOJ 3307: 雨天的尾巴 线段树合并 树上差分
- [BZOJ]3307: 雨天的尾巴 线段树合并+树上差分
- BZOJ_3307_雨天的尾巴_线段树合并+树上差分
- bzoj 3307: 雨天的尾巴【树剖lca+树上差分+线段树合并】
- bzoj 3307: 雨天的尾巴 (线段树合并+LCA)
- [BZOJ3307][线段树合并]雨天的尾巴
- BZOJ 3307: 雨天的尾巴( LCA + 线段树合并 )
- 【bzoj3307】雨天的尾巴 权值线段树合并
- BZOJ3307 雨天的尾巴 (树链剖分 线段树合并 dfs相关)
- 【BZOJ3307】雨天的尾巴 线段树合并
- [bzoj3307]雨天的尾巴_线段树合并
- 【BZOJ3307】雨天的尾巴(树链剖分+树上差分+线段树)
- bzoj 3307: 雨天的尾巴 线段树
- BZOJ 3307 雨天的尾巴 线段树
- [BZOJ3307][雨天的尾巴][树链剖分+线段树]
- [bzoj3307]雨天的尾巴【线段树】
- BZOJ 3307 雨天的尾巴 树上差分+lca+权值线段树合并
- BZOJ 3307: 雨天的尾巴
- BZOJ3307 雨天的尾巴
- [bzoj3307]雨天的尾巴