заглавие
Описание
Пусть Т корневое дерево, мы делаем следующее определение:
• а и б представлены в двух различных узлах T. Если вы являетесь б предков, то называется «умным, чем б не знает, куда идти.»
• а и б представлены в двух различных узлах T. Если а и б деревьев на расстоянии не превышает заданную константу х, то называется «а и б смеются.»
Принимая во внимание п узлы корневого дерева T, узел с номерами 1 ~ п, корневой узел является номер узла. Вы должны ответить на запрос Q, запрос даны два целых числа р и к, спросил , сколько упорядоченных троек \ ((а, б, в ) \) выполнено:
- а, б и в три разные точки Т и р а это номер узла;
- с и б, чем умный, не знаю, куда идти;
- а и б смех. К является постоянной Представленная здесь говорим.
анализ
Сегмент дерево слияния.
Из - за претензии триплет \ ((A, B, C ) \) в \ (а, Ь \) являются \ (С \) предков, только две ситуации
\ (Ь \) является \ (A \) предков
Статистика как этот случай непосредственно, ответ \ (\ мин \ {глубина ( а) -1, к \} (размер (а) -1) \) , где \ (глубина (а) \) из \ (А \) глубина, \ (размер (а) \) является размер поддерева
\ (А \) является \ (B \) предков
Выберите любой, чтобы соответствовать требованиям \ (Ь \) , то \ (Ь \) поддерево необязательно \ (с \) может удовлетворить ответ. Ответ \ (\ глубина СУММА \ limits_ {(А) + k≥depth (В)} размер (В) -1 \) . Для того, чтобы эта вещь , чтобы вычислить, для каждого узла сохраняет глубину номер , чтобы \ (размер (х) -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;
}