bzoj 4756 Promotion Counting —— 线段树合并

本文深入解析了线段树合并子树权值的算法实现,通过具体代码示例展示了如何利用DFS算法进行树状结构的数据处理。文章涵盖了线段树的构建、更新和查询操作,特别聚焦于树状结构中节点权值的高效合并。

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4756

合并子树的权值线段树;

merge 返回 int 或者是 void 都可以。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
using namespace std;
int const xn=1e5+5,xm=xn*20;//
int n,p[xn],b[xn],hd[xn],ct,to[xn<<1],nxt[xn<<1];
int cnt,rt[xn],ls[xm],rs[xm],sum[xm],ans[xn],tot;
int rd()
{
  int ret=0,f=1; char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
  while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
  return f?ret:-ret;
}
int gt[20];
void wr(int x)
{
  if(!x){puts("0"); return;}
  if(x<0)putchar('-'),x=-x;
  int t=0;
  while(x)gt[++t]=x%10,x/=10;
  for(int i=t;i;i--)putchar(gt[i]+'0');
  puts("");
}
void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
void merge(int &x,int y)
{
  if(!x){x=y; return;}
  sum[x]+=sum[y];
  if(ls[y])merge(ls[x],ls[y]);//if
  if(rs[y])merge(rs[x],rs[y]);//if
}
/*
int merge(int x,int y,int l,int r)
{
  if(!x||!y)return x+y;
  sum[x]+=sum[y];
  if(l==r)return x;
  ls[x]=merge(ls[x],ls[y],l,mid);
  rs[x]=merge(rs[x],rs[y],mid+1,r);
  return x;
}
*/
void add(int &x,int l,int r,int pos)
{
  if(!x)x=++cnt; sum[x]++;
  if(l==r)return;
  if(pos<=mid)add(ls[x],l,mid,pos);
  else add(rs[x],mid+1,r,pos);
}
int query(int x,int l,int r,int L,int R)
{
  if(!x)return 0;
  if(l>=L&&r<=R)return sum[x];
  int ret=0;
  if(mid>=L)ret+=query(ls[x],l,mid,L,R);
  if(mid<R)ret+=query(rs[x],mid+1,r,L,R);
  return ret;
}
void dfs(int x)
{
  for(int i=hd[x],u;i;i=nxt[i])
    {
      dfs(u=to[i]);
      //      rt[x]=merge(rt[x],rt[u],1,tot);
      merge(rt[x],rt[u]);
    }
  ans[x]=query(rt[x],1,tot,p[x],tot);
  add(rt[x],1,tot,p[x]);
}
int main()
{
  n=rd();
  for(int i=1;i<=n;i++)p[i]=rd(),b[i]=p[i];
  sort(b+1,b+n+1); tot=unique(b+1,b+n+1)-b-1;
  for(int i=1;i<=n;i++)p[i]=lower_bound(b+1,b+tot+1,p[i])-b;
  for(int i=2,fa;i<=n;i++)fa=rd(),add(fa,i);
  dfs(1);
  for(int i=1;i<=n;i++)wr(ans[i]);
  return 0;
}

 

转载于:https://www.cnblogs.com/Zinn/p/9868726.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值