LUOGU 3899 : [호남 교육] 웃음 세그먼트 트리 합병

표제

LUOGU 3899

기술

우리는 다음과 같은 정의를 만들 T는 뿌리 트리하자 :

• a와 b는 T.의 두 개의 서로 다른 노드에 제공 당신이 나 조상이있는 경우, "어디로 모르는 나보다 똑똑한"이라고합니다.

• a와 b는 T.의 두 개의 서로 다른 노드에 제공 a와 주어진 상수 X를 초과하지 않는 거리에서 나무의 B 경우, "a와 b가 웃고있다."라고

는 n 노드 뿌리 트리 (T)를 감안할 때, 노드가 ~ n은 1 번호가, 루트 노드는 노드 번호입니다. 당신은 질문 문의에 대답 할 필요가 질문 두 개의 정수 p와 K 주어진 트리플을 주문 얼마나 많은 질문 (를 A, B, C (\ ) \) 만족 :

  1. A, B 및 C는 세 가지 점은 T이며, P (A)는 노드의 수이고;
  2. 영리한보다는 C와 B는하지 어디로 가야 알고;
  3. A 및 B 웃. K는 여기에 주어진 상수는 이야기입니다.

분석

세그먼트 트리 병합.

때문에 제 삼중 \ ((A, B, C ) \) 에서 \ (A, B \)가 된다 (\ C \) 의 선조의 두 상황

  • \ (b의 \)가 된다 (a \) \ 조상

    바로이 경우 같은 통계 해답 \ (\ 분 \ {깊이 ( a) -1, k 개의 \} (크기 (a) -1) \) 여기서 \ (깊이 (a) \)\ (A \) 의 깊이, \는 (크기는 (a) \) 의 서브 트리의 크기

  • \ (a \)가 된다 (B 형 \) \ 조상

    의 요구 사항을 충족시킬 수있는 하나의 선택 \ (ㄱ \) 다음을, (B \) \ 하위 트리 선택적 \ (ㄴ \) 답을 만족시킬 수 있습니다. 대답이 \ (\ 합 \ limits_의 깊이 {(A) + k≥depth (B)} 크기 (B) -1 \) . 이 점은 계산하기 위해, 각 노드에 대해 깊이 번호가 유지 () 크기 (X -1 \는 \ ) 세그먼트 트리의 무게마다 결합 된 서브 트리까지의 구간 트리.

열려면 참고 long long.

암호

#include<bits/stdc++.h>

typedef long long ll;
const int maxn=3e5+10;
typedef int iarr[maxn];

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }

    char Out[1<<24],*fe=Out;
    inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
    template<typename T>inline void write(T x,char str)
    {
        if (!x) *fe++=48;
        if (x<0) *fe++='-', x=-x;
        T num=0, ch[20];
        while (x) ch[++num]=x%10+48, x/=10;
        while (num) *fe++=ch[num--];
        *fe++=str;
    }
}

using IO::read;
using IO::write;

template<typename T>inline T min(T a,T b) { return a<b ? a : b; }
template<typename T>inline T max(T a,T b) { return a>b ? a : b; }

int ver[maxn<<1],Next[maxn<<1],head[maxn],len;
inline void add(int x,int y)
{
    ver[++len]=y,Next[len]=head[x],head[x]=len;
}

namespace SGT
{
    struct Orz{int l,r;ll z;}c[maxn*30];
    int num=0;
    inline void Change(int &x,int l,int r,int k,int z)
    {
        if (!x) x=++num;
        c[x].z+=z;
        if (l==r) return ;
        int mid=(l+r)>>1;
        if (k<=mid) Change(c[x].l,l,mid,k,z);
        else Change(c[x].r,mid+1,r,k,z);
    }

    inline ll query(int x,int l,int r,int tl,int tr)
    {
        if (!x || tr<tl) return 0;
        if (tl<=l && r<=tr) return c[x].z;
        int mid=(l+r)>>1; ll ans=0;
        if (tl<=mid) ans+=query(c[x].l,l,mid,tl,tr);
        if (tr>mid) ans+=query(c[x].r,mid+1,r,tl,tr);
        return ans;
    }

    inline int merge(int x,int y)
    {
        if (!x || !y) return x|y;
        int t=++num;
        c[t].l=merge(c[x].l,c[y].l);
        c[t].r=merge(c[x].r,c[y].r);
        c[t].z=c[x].z+c[y].z;
        return t;
    }
}

using SGT::Change;
using SGT::query;
using SGT::merge;

iarr rt,siz,dep;
int n,q;
inline void dfs(int x,int f)
{
    siz[x]=1;
    dep[x]=dep[f]+1;
    for (int i=head[x]; i; i=Next[i])
    {
        int y=ver[i];
        if (y==f) continue;
        dfs(y,x);
        siz[x]+=siz[y];
    }
    Change(rt[x],1,n,dep[x],siz[x]-1);
    if (f) rt[f]=merge(rt[f],rt[x]);
}

int main()
{
    read(n);read(q);
    for (int i=1,x,y; i<n; ++i) read(x),read(y),add(x,y),add(y,x);
    dfs(1,0);
    while (q--)
    {
        int x,y;read(x);read(y);
        write(query(rt[x],1,n,dep[x]+1,dep[x]+y)+1ll*(siz[x]-1)*min(dep[x]-1,y),'\n');
    }
    IO::flush();
    return 0;
}

추천

출처www.cnblogs.com/G-hsm/p/11420524.html