ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【题解】[CJOI2019] 树上查询(树状数组)

2019-08-30 23:01:35  阅读:244  来源: 互联网

标签:const 树状 int 题解 register 查询 now 节点 CJOI2019


【题解】[CJOI2019] 树上查询(树状数组)

题目描述

班⻓小 A 需要管理信息组的日常纪律。所有人都在树形机房学习,树形机房的根节点为 1 。信息组的同学很多,但树
形机房的每个节点上有且仅有一个同学。小 A 的位置在树形机房的某个节点上,他想要管理在他所站节点子树中的同学(不算自己)。每个位置都有一个管理容易值\(w_i\) ,他能管理到某个位置 ,当且仅当他们的距离不超过\(w_i\)。

定位一个根\(x\),现在就是求\(u\in S\),\(S\)是\(x\)的所有子树所有节点集合,询问多少个\(u\)满足这样一个条件
\[ d[u]-d[x]\le w[u] \]
其中\(d[u]\)表示\(u\)到根的距离

变化一下就是
\[ d[x]\ge d[u]-w[u] \]
现在对于确定的\(x\),问题就变成了查询在他子树内有多少满足条件的\(u\)。由于\(d[u]-w[u]\)仅和\(u\)有关,直接\(O(n)\)预处理出\(d[u]-w[u]\)。

考虑如何查询满足\(d[u]-w[u]\)的个数,我们开个桶\(c[]\)维护每个\(d[u]-w[u]\) 的满足条件\(u\)的个数,由于我们直接查询的是前缀和,所以树状数组动态维护前缀和。

考虑如何得到子树内的满足条件\(u\)的个数,由于我们对于每个点都要在线查询\(\sum_{i\le d[x]} c[i]\le d[x]\)来得到答案,所以显然不能清空树状数组然后再进去子树查询。

考虑这样一种做法,就是在处理当前节点子树前,先查询一遍答案,这部分答案是不要的,递归处理完子树的节点后,再查询一遍答案。将第二次查询到的答案减去第一次得到的答案就是我们要的答案。

复杂度\(O(n\log n)\)

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;  typedef long long ll;
inline int qr(){
      register int ret=0,f=0;
      register char c=getchar();
      while(c<48||c>57)f|=c==45,c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return f?-ret:ret;
}

const int maxn=2e5+5;
struct E{
      int to,nx,w;
      E(){to=nx=w=0;}
      E(const int&a,const int&b,const int&c){to=a; nx=b; w=c;}
}e[maxn<<1];
ll d[maxn],sav[maxn<<1],cha[maxn];
int head[maxn],w[maxn],len,seg[maxn<<1],ans[maxn];
int n,cnt,t0;

inline void add(const int&fr,const int&to,const int&w,const int&f=1){
      e[++cnt]=E(to,head[fr],w);
      head[fr]=cnt;
      if(f)add(to,fr,w,0);
}

inline void add(const int&pos,const int&tag){
      for(register int t=pos;t<=len;t+=t&-t) seg[t]+=tag;
}

inline int q(const int&pos){
      register int ret=0;
      for(register int t=pos;t>0;t-=t&-t) ret+=seg[t];
      return ret;
}

void dfs1(const int&now,const int&last){
      for(register int t=head[now];t;t=e[t].nx)
        if(e[t].to!=last)
          d[e[t].to]=d[now]+e[t].w,dfs1(e[t].to,now);
      sav[++t0]=d[now]; sav[++t0]=cha[now]=d[now]-w[now];
}

void dfs2(const int&now,const int&last){
      ans[now]-=q(d[now]);
      for(register int t=head[now];t;t=e[t].nx)
        if(e[t].to!=last) dfs2(e[t].to,now);
      ans[now]+=q(d[now]); add(cha[now],1);
}

int main(){
      freopen("A.in","r",stdin);
      freopen("A.out","w",stdout);
      n=qr();
      for(register int t=1;t<=n;++t) w[t]=qr();
      for(register int t=2,t1,t2;t<=n;++t)
        t1=qr(),t2=qr(),add(t,t1,t2);
      dfs1(1,0);
      sort(sav+1,sav+t0+1);  len=unique(sav+1,sav+t0+1)-sav-1;
      for(register int t=1;t<=n;++t)
        d[t]=lower_bound(sav+1,sav+len+1,d[t])-sav,cha[t]=lower_bound(sav+1,sav+len+1,cha[t])-sav;
      dfs2(1,0);
      for(register int t=1;t<=n;++t) printf("%d\n",ans[t]);
      return 0;
}

标签:const,树状,int,题解,register,查询,now,节点,CJOI2019
来源: https://www.cnblogs.com/winlere/p/11437490.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有