bzoj 3307: 雨天的尾巴 (线段树合并+LCA)
2017-05-26 20:14
369 查看
题目描述
传送门
题目大意:N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。题解
如果我们修改了一条路径,那么在x,y处+1, lca(x,y),fa[lca(x,y)]处-1,那么对于每个点查询他的子树就能得到他的答案。其实就是树上差分。对于每个位置维护以颜色为下标的线段树(动态开点),每个位置维护每个颜色在当前点的所有修改。
那么我们进行线段树合并,当一个点的所有子树都合并完成后,现在这个点线段树中的信息就是答案。
代码
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #define N 100003 using namespace std; int tot,point ,nxt[N*2],v[N*2],deep ,fa [20],mi[20]; struct data{ int l,r,x,opt; }tr[N*70]; int n,m,ans ,sz,top,st ,root ; struct node{ int x,y,c; }p ; void add(int x,int y) { tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; } void dfs(int x,int f) { deep[x]=deep[f]+1; for (int i=1;i<=17;i++) { if (deep[x]-mi[i]<0) break; fa[x][i]=fa[fa[x][i-1]][i-1]; } for (int i=point[x];i;i=nxt[i]) { if (v[i]==f) continue; fa[v[i]][0]=x; dfs(v[i],x); } } int lca(int x,int y) { if (deep[x]<deep[y]) swap(x,y); int k=deep[x]-deep[y]; for (int i=0;i<=17;i++) if ((k>>i)&1) x=fa[x][i]; if (x==y) return x; for (int i=17;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } void update(int now) { int l=tr[now].l; int r=tr[now].r; if (tr[l].x>=tr[r].x) tr[now].x=tr[l].x,tr[now].opt=tr[l].opt; else tr[now].x=tr[r].x,tr[now].opt=tr[r].opt; } void insert(int &i,int l,int r,int x,int v) { if (!i) i=++sz; if (l==r) { tr[i].x+=v; tr[i].opt=l; return; } int mid=(l+r)/2; if (x<=mid) insert(tr[i].l,l,mid,x,v); else insert(tr[i].r,mid+1,r,x,v); update(i); } int merge(int x,int y,int l,int r) { if (!x) return y; if (!y) return x; if (l==r) { tr[x].x+=tr[y].x; tr[x].opt=l; return x; } int mid=(l+r)/2; tr[x].l=merge(tr[x].l,tr[y].l,l,mid); tr[x].r=merge(tr[x].r,tr[y].r,mid+1,r); update(x); return x; } void solve(int x,int f) { for (int i=point[x];i;i=nxt[i]) { if (v[i]==f) continue; solve(v[i],x); root[x]=merge(root[x],root[v[i]],1,top); } int t=root[x]; if (t) ans[x]=st[tr[t].opt]; else ans[x]=0; } int main() { freopen("a.in","r",stdin); freopen("my.out","w",stdout); scanf("%d%d",&n,&m); mi[0]=1; for (int i=1;i<=18;i++) mi[i]=mi[i-1]*2; for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); } dfs(1,0); for (int i=1;i<=m;i++) { scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].c); st[++top]=p[i].c; } sort(st+1,st+top+1); top=unique(st+1,st+top+1)-st-1; for (int i=1;i<=m;i++) p[i].c=lower_bound(st+1,st+top+1,p[i].c)-st; for (int i=1;i<=m;i++) { int t=lca(p[i].x,p[i].y); insert(root[p[i].x],1,top,p[i].c,1); insert(root[p[i].y],1,top,p[i].c,1); insert(root[t],1,top,p[i].c,-1); if (fa[t][0]) insert(root[fa[t][0]],1,top,p[i].c,-1); } solve(1,0); for (int i=1;i<=n;i++) printf("%d\n",ans[i]); }
相关文章推荐
- bzoj 3307: 雨天的尾巴【树剖lca+树上差分+线段树合并】
- BZOJ 3307: 雨天的尾巴( LCA + 线段树合并 )
- 【BZOJ3307】雨天的尾巴 线段树合并
- 【bzoj3307】雨天的尾巴 权值线段树合并
- [BZOJ3307][线段树合并]雨天的尾巴
- [BZOJ]3307: 雨天的尾巴 线段树合并+树上差分
- BZOJ_3307_雨天的尾巴_线段树合并+树上差分
- [bzoj3307]雨天的尾巴_线段树合并
- BZOJ 3307: 雨天的尾巴 线段树合并 树上差分
- BZOJ3307 雨天的尾巴 (树链剖分 线段树合并 dfs相关)
- 【BZOJ3307】雨天的尾巴-线段树合并+树上差分
- [bzoj3307]雨天的尾巴【线段树】
- BZOJ 3307 雨天的尾巴 线段树
- [BZOJ3307][雨天的尾巴][树链剖分+线段树]
- bzoj 3307: 雨天的尾巴 线段树
- [bzoj3307]雨天的尾巴
- bzoj 3307 雨天的尾巴
- bzoj3307 雨天的尾巴
- bzoj 3307: 雨天的尾巴
- 【BZOJ 3307】 3307: 雨天的尾巴 (线段树+树链剖分)