P4556 雨天的尾巴(线段树合并)

LawrenceSivan·2021-04-20 16:34·155 次阅读

P4556 雨天的尾巴(线段树合并)

对于值域线段树,如果他们维护相同的值域,那么他们对各个子区间的划分是一致的,于是暗示着我们这些线段树是具有可合并性的。

我们可以使用两个指针以递归形式同步遍历这两棵线段树,也就是他们始终指向同一个区间。

显然地,会有两种情况:

Copy
1,其中有一个是空的,那么我们取另一个不空的作为新线段树的节点 2,两个都不为空,那么递归合并这两棵线段树的左右子树,最后删除一个,留下另一个,自底向上更新信息。

常见的写法有两种,它们各有利弊:

第一种,我们直接把两个合起来,也就是说,其中一个的结构会被破坏,这也就意味着如果合并后还有操作针对于被合并了的的某棵线段树那么我们就GG,于是只能离线去搞。

但是优点就是省空间。

Copy
int merge(int p,int q,int l,int r){ if(!p||!q)return p+q; if(l==r){ dat[p]+=dat[q]; t[p]=l; return p; } int mid=(l+r)>>1; L[p]=merge(L[p],L[q],l,mid); R[p]=merge(R[p],R[q],mid+1,r); push_up(p); return p; }

第二种,我们可以开出一个新的节点来存放合并后的树,这样我们原来的线段树的结构不变就得到了保障,这样就可以在线了。

缺点自然也很显然,每次合并我们都要重开一个新的节点,于是空间是炸的。

Copy
int merge(int p,int q,int l,int r) { if(!p||!q)return p+q; int rt=++tot; if(l==r){ dat[rt]=dat[p]+dat[q]; t[rt]=l; return rt; } int mid=(x+y)>>1; L[root]=merge(L[p],L[q],l,mid); R[root]=merge(R[p],R[q],mid+1,r); pushup(rt); return rt; }

根据情况权衡利弊以后谨慎使用吧

如果空间卡的死,又保证不对被合并过的树进行操作,那就选第一种。

要是要求在线保留树的结构,空间不严格那就第二种。

其他的部分对普通权值线段树微改一下就好了,没什么太大的区别;

复杂度是O(mlogn)的,很高效了

例题:P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并

题目很简单,我们直接把z当成值域,每一个节点维护一个权值线段树。

然后针对每次放粮我们直接树上差分,uv的路径直接处理成u+1,v+1,lca(u,v)1,fa[lca(u,v)]1就好了,最后我们做一次树上前缀和就可了

Copy
//#define LawrenceSivan #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; #define INF 0x3f3f3f3f #define re register const int maxn=1e5+5; const int maxm=6e6+5; inline int mymax(int a,int b){ return a>b?a:b; } inline int mymin(int a,int b){ return a<b?a:b; } int n,m,MAX,tot; int X[maxn],Y[maxn],Z[maxn],ans[maxn],root[maxn]; int L[maxm],R[maxm],dat[maxm],t[maxm]; int head[maxn],nxt[maxn<<1],to[maxn<<1],cnt; inline void add(int u,int v){ nxt[++cnt]=head[u]; to[cnt]=v; head[u]=cnt; } int fa[maxn],top[maxn],size[maxn],son[maxn],dep[maxn]; void dfs1(int u,int f){ size[u]=1; fa[u]=f; dep[u]=dep[f]+1; for(re int i=head[u];i;i=nxt[i]){ int v=to[i]; if(v==f)continue; dfs1(v,u); size[u]+=size[v]; if(size[v]>size[son[u]]){ son[u]=v; } } } void dfs2(int u,int topf){ top[u]=topf; if(!son[u])return; dfs2(son[u],topf); for(re int i=head[u];i;i=nxt[i]){ int v=to[i]; if(v==topf||v==son[u]||top[v])continue; dfs2(v,v); } } inline int lca(int u,int v){ while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]])swap(u,v); u=fa[top[u]]; } return dep[u]<dep[v]?u:v; } inline void push_up(int rt){ if(dat[L[rt]]>=dat[R[rt]])dat[rt]=dat[L[rt]],t[rt]=t[L[rt]]; else dat[rt]=dat[R[rt]],t[rt]=t[R[rt]]; } int modify(int rt,int l,int r,int pos,int val){ if(!rt)rt=++tot; if(l==r){ dat[rt]+=val; t[rt]=l; return rt; } int mid=(l+r)>>1; if(pos<=mid)L[rt]=modify(L[rt],l,mid,pos,val); else R[rt]=modify(R[rt],mid+1,r,pos,val); push_up(rt); return rt; } int merge(int p,int q,int l,int r){ if(!p||!q)return p+q; if(l==r){ dat[p]+=dat[q]; t[p]=l; return p; } int mid=(l+r)>>1; L[p]=merge(L[p],L[q],l,mid); R[p]=merge(R[p],R[q],mid+1,r); push_up(p); return p; } void solve(int u){ for(re int i=head[u];i;i=nxt[i]){ int v=to[i]; if(dep[v]>dep[u])solve(v),root[u]=merge(root[u],root[v],1,MAX); if(dat[root[u]])ans[u]=t[root[u]]; } } inline int read(){ int x=0, f=1;char ch=getchar(); while (!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();} while (isdigit(ch)){x=x*10+(ch^48);ch=getchar();} return x*f; } int main() { #ifdef LawrenceSivan freopen("aa.in", "r", stdin); freopen("aa.out", "w", stdout); #endif n=read();m=read(); for(re int i=1,u,v;i<n;i++){ u=read();v=read(); add(u,v); add(v,u); } dfs1(1,0); dfs2(1,1); for(re int i=1;i<=m;i++){ X[i]=read();Y[i]=read();Z[i]=read(); MAX=mymax(Z[i],MAX); } for(re int i=1;i<=m;i++){ int LCA=lca(X[i],Y[i]); root[X[i]]=modify(root[X[i]],1,MAX,Z[i],1); root[Y[i]]=modify(root[Y[i]],1,MAX,Z[i],1); root[LCA]=modify(root[LCA],1,MAX,Z[i],-1); if(fa[LCA])root[fa[LCA]]=modify(root[fa[LCA]],1,MAX,Z[i],-1); } solve(1); for(re int i=1;i<=n;i++){ printf("%d\n",ans[i]); } return 0; }
posted @   LawrenceSivan  阅读(155)  评论(0编辑  收藏  举报
编辑推荐:
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
· .NET 进程 stackoverflow异常后,还可以接收 TCP 连接请求吗?
阅读排行:
· 本地部署 DeepSeek:小白也能轻松搞定!
· 基于DeepSeek R1 满血版大模型的个人知识库,回答都源自对你专属文件的深度学习。
· 在缓慢中沉淀,在挑战中重生!2024个人总结!
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 大人,时代变了! 赶快把自有业务的本地AI“模型”训练起来!
点击右上角即可分享
微信分享提示