BZOJ3307 雨天的尾巴 (树链剖分 线段树合并 dfs相关)
来源:互联网 发布:武汉知黛化妆品靠谱吗 编辑:程序博客网 时间:2024/05/01 04:56
题目大意
N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。
题解
看到这道题之后我本能的想法就是位置线段树套权值线段树的,但是看了一下,这道题的时间限制和空间限制卡得都比较紧,而且是离线问题,树套树卡起来应该是十分的困难的。
这道题虽然是处理树上问题,但是我们先考虑如何处理这样的区间问题。 如果所有的操作和询问都是在区间上进行的话,如在[x,y]区间内各放置一个z物品,就在x位置打上z物品+1的标记,在y+1位置打上z物品-1的标记。从左到右扫、处理标记,用一棵权值线段树维护。
从区间问题转化到了树上问题,通过这道题我学到了一种新的手段。
每次在一个树上路径上进行修改的时候,如修改x到y的路径的时候,只需要在x和y各打一个z物品+1的标记,在lca和fa[lca]打上z物品-1的标记,这样在dfs递归求解、向上合并的时候就可以做到不重不漏了。
因为在x和y打一个标记,这个标记的作用范围分别是x和y到根的路径(因为被这个标记修改后的线段树会一路被合并到根节点),但是从lca到根的路径上是被这个标记作用了两次的。所以给lca打上z物品-1的标记之后,lca到根的路径这个标记就只作用一次了;再给fa[lca]打上z物品-1的标记,这样这个标记就恰好只覆盖从x到y的路径了。
所以大概的思路就是:
- 处理出各个结点的标记
- 自下向上合并线段树
- 处理标记,修改线段树
- 把答案记录下来
代码
#include <cstdio>#include <iostream>#include <vector>#include <algorithm>using namespace std;const int maxn=int(1e5)+111, inf=int(1e9)+7;int n,m;int Tot=0,head[maxn];struct Edge { int to,next; Edge() {} Edge(int y,int nx):to(y),next(nx) {}}eage[maxn*2];inline void add(int x,int y) { eage[Tot]=Edge(y,head[x]), head[x]=Tot++; eage[Tot]=Edge(x,head[y]), head[y]=Tot++; return;}int fa[maxn],siz[maxn],dep[maxn],son[maxn];void dfs1(register int u) { siz[u]=1, son[u]=0; for(register int i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa[u]) { fa[eage[i].to]=u; dep[eage[i].to]=dep[u]+1; dfs1(eage[i].to); siz[u]+=siz[eage[i].to]; if(siz[eage[i].to]>siz[son[u]]) son[u]=eage[i].to; } return;}int top[maxn],seq[maxn],id[maxn],ind;void dfs2(register int u) { seq[id[u]=++ind]=u; if(u==son[fa[u]]) top[u]=top[fa[u]]; else top[u]=u; if(son[u]) dfs2(son[u]); for(register int i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa[u] && eage[i].to!=son[u]) dfs2(eage[i].to); return;}inline int LCA(int u,int v) { while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]]) std::swap(u,v); u=fa[top[u]]; } return dep[u]<dep[v]?u:v;}vector<pair<int,int> > op[maxn];#define pb push_back#define mp make_pairint v[maxn],vtop;struct Oper { int x,y,z;}q[maxn];struct Node { int ls,rs; pair<int,int> pos; inline Node() { ls=rs=0; pos=mp(0,0); }}node[int(2e6)];int root[maxn],tot=0;int ans[maxn];inline void seg_merge(int k1,int k2,int l,int r) { if(l==r) { node[k1].pos.first+=node[k2].pos.first; return; } register int &ls=node[k1].ls, &rs=node[k1].rs, mid=(l+r)>>1; if(node[k2].ls) { if(!ls) ls=node[k2].ls; else seg_merge(ls,node[k2].ls,l,mid); } if(node[k2].rs) { if(!rs) rs=node[k2].rs; else seg_merge(rs,node[k2].rs,mid+1,r); } if(ls) node[k1].pos=max(node[k1].pos,node[ls].pos); if(rs) node[k1].pos=max(node[k1].pos,node[rs].pos); return;}inline void seg_modify(int k,int l,int r,int pos,int val) { if(l==r) { node[k].pos.first+=val, node[k].pos.second=-pos; return; } register int &ls=node[k].ls, &rs=node[k].rs, mid=(l+r)>>1; if(pos<=mid) { if(!ls) ls=++tot; seg_modify(ls,l,mid,pos,val); if(!node[ls].pos.first) ls=0; } else { if(!rs) rs=++tot; seg_modify(rs,mid+1,r,pos,val); if(!node[rs].pos.first) rs=0; } if(ls && rs) node[k].pos=max(node[ls].pos,node[rs].pos); else if(ls) node[k].pos=node[ls].pos; else if(rs) node[k].pos=node[rs].pos; else node[k].pos=mp(0,0); return;}inline void dfs(register int u) { root[u]=++tot; for(register int i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa[u]) { dfs(eage[i].to); seg_merge(root[u],root[eage[i].to],1,vtop); } for(register int i=0;i<(int)op[u].size();i++) { seg_modify(root[u],1,vtop,op[u][i].first,op[u][i].second); } ans[u]=-node[root[u]].pos.second; return;}int main() {#ifndef ONLINE_JUDGE freopen("input0.txt","r",stdin); freopen("output.txt","w",stdout);#endif // ONLINE_JUDGE scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) head[i]=-1; for(int x,y,i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); } dfs1(1),dfs2(1); for(int i=1;i<=m;i++) { scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].z); v[++vtop]=q[i].z; } sort(v+1,v+1+vtop); vtop=unique(v+1,v+1+vtop)-(v+1); for(int i=1;i<=m;i++) { int x=q[i].x, y=q[i].y, z=lower_bound(v+1,v+1+vtop,q[i].z)-v; op[x].pb(mp(z,+1)), op[y].pb(mp(z,+1)); int lca=LCA(x,y); op[lca].pb(mp(z,-1)), op[fa[lca]].pb(mp(z,-1)); } dfs(1); for(int i=1;i<=n;i++) printf("%d\n",v[ans[i]]); return 0;}
1 2
- BZOJ3307 雨天的尾巴 (树链剖分 线段树合并 dfs相关)
- [BZOJ3307][线段树合并]雨天的尾巴
- bzoj3307雨天的尾巴(线段树合并)
- 【bzoj3307】雨天的尾巴 线段树+树链剖分
- [BZOJ3307][雨天的尾巴][树链剖分+线段树]
- 【BZOJ3307】雨天的尾巴(树链剖分+树上差分+线段树)
- bzoj3307 雨天的尾巴
- [bzoj3307]雨天的尾巴
- BZOJ3307: 雨天的尾巴
- 【BZOJ3307】雨天的尾巴(权限题)
- bzoj 3307: 雨天的尾巴 (线段树合并+LCA)
- BZOJ3307——雨天的尾巴
- BZOJ 3307 雨天的尾巴 线段树
- bzoj 3307: 雨天的尾巴 线段树
- BZOJ 3307: 雨天的尾巴 线段树合并 树上差分
- BZOJ 3307 雨天的尾巴 树上差分+lca+权值线段树合并
- 雨天的尾巴
- [JZOJ3397]雨天的尾巴
- sybase复制服务
- xml解析
- ViewPager 调用 notifyDataSetChanged()无刷新
- webpack~关于使用包详解(随时更新)
- entrySet() ,keySet()的区别
- BZOJ3307 雨天的尾巴 (树链剖分 线段树合并 dfs相关)
- Java length、length()、size()区别
- 删除用户时提示“数据库主体在该数据库中拥有架构”无法删除解决办法
- Js控制文本框只能输入数字或小数点
- Git项目管理+Unity游戏开发——在Git上布置一个Unity空项目
- js中escape,encodeURI和encodeURIComponent区别
- 彻底弄懂活动四大启动模式
- java学习笔记------数组
- java实现excel的导入导出(poi详解)