C67 线段树合并 P3899 [湖南集训] 更为厉害

视频链接:253 线段树合并 P3899 [湖南集训] 更为厉害_哔哩哔哩_bilibili

 

 

 

C64 可持久化线段树+DFS P3899 [湖南集训] 更为厉害 - 董晓 - 博客园 (cnblogs.com)

Luogu P3899 [湖南集训] 更为厉害

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

void read(int &x){ //快读
  x=0; char c=getchar();
  while(!isdigit(c))c=getchar();
  while(isdigit(c))x=x*10+c-'0',c=getchar();
}
#define LL long long
#define mid (l+r)/2
#define N 300005
int n,m;
vector<int>g[N];   //邻接表
int dep[N],siz[N]; //树信息
int root[N],tot;   //根节点,开点个数
int ls[N*40],rs[N*40];LL sum[N*40]; //sum:权值和

void change(int &u,int l,int r,int p,int v){ //点修
  if(!u)u=++tot; //开点
  if(l==r){sum[u]+=v; return;}
  if(p<=mid)change(ls[u],l,mid,p,v);
  else change(rs[u],mid+1,r,p,v);
  sum[u]=sum[ls[u]]+sum[rs[u]];
}
int merge(int x,int y){ //合并
  if(!x||!y)return x+y;
  int cur=++tot; //开点
  sum[cur]=sum[x]+sum[y];
  ls[cur]=merge(ls[x],ls[y]);
  rs[cur]=merge(rs[x],rs[y]);
  return cur;
}
void dfs(int x,int f){ //递归合并
  dep[x]=dep[f]+1; siz[x]=1;
  for(int y:g[x]){
    if(y==f)continue;
    dfs(y,x);
    siz[x]+=siz[y];
    root[x]=merge(root[x],root[y]);
  }
  change(root[x],1,n,dep[x],siz[x]-1);
}
LL query(int u,int l,int r,int x,int y){ //区查
  if(x<=l&&r<=y) return sum[u];
  LL s=0;
  if(x<=mid)s+=query(ls[u],l,mid,x,y);
  if(y>mid)s+=query(rs[u],mid+1,r,x,y);
  return s;
}
int main(){
  read(n),read(m);
  for(int i=1,x,y; i<n; i++){
    read(x),read(y);
    g[x].push_back(y);g[y].push_back(x);
  }
  dfs(1,0);
  for(int i=1,a,k; i<=m; i++){
    read(a),read(k);
    LL ans=1ll*min(k,dep[a]-1)*(siz[a]-1)
       +query(root[a],1,n,dep[a]+1,min(dep[a]+k,n));
    printf("%lld\n",ans);
  }
}

 

posted @ 2023-11-15 21:49  董晓  阅读(183)  评论(0编辑  收藏  举报