[湖南集训]谈笑风生

嘟嘟嘟


这题刚开始犹豫了一会儿,以为“高明”的优先级大于“谈笑风生”,不过样例表明只要两点间距离不超过(x),两人就算”谈笑风生“。
接下来看看怎么回答询问。
首先(a)是固定的,且(a,b)都是(c)的祖先。那就得分类讨论:
1.(b)(a)的祖先,那么(c)就是(a)的子树中的所有点,根据乘法原理,三元组个数为((size[a] - 1) * min(deep[a], x))
2.(a)(b)的祖先。那么对于(a)子树内的每一个(b),合法的(c)都有(b)的子树大小个,所以这种情况三元组个数为(sum _ {b in a的子树,dis(a, b) leqslant a} size[b] - 1)。至于怎么求这些合法的(b),显然就是基于(dfs)序的主席树啦。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<assert.h>
using namespace std;
#define enter puts("") 
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 3e5 + 5;
In ll read()
{
  ll ans = 0;
  char ch = getchar(), last = ' ';
  while(!isdigit(ch)) last = ch, ch = getchar();
  while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
  if(last == '-') ans = -ans;
  return ans;
}
In void write(ll x)
{
  if(x < 0) x = -x, putchar('-');
  if(x >= 10) write(x / 10);
  putchar(x % 10 + '0');
}
In void MYFILE()
{
#ifndef mrclr
  freopen(".in", "r", stdin);
  freopen(".out", "w", stdout);
#endif
}

int n, m;
struct Edge
{
  int nxt, to;
}e[maxn << 1];
int head[maxn], ecnt = -1;
In void addEdge(int x, int y)
{
  e[++ecnt] = (Edge){head[x], y};
  head[x] = ecnt;
}

struct Tree
{
  int ls, rs;
  ll sum;
}t[maxn * 40];
int root[maxn], tcnt = 0;
In void insert(int old, int& now, int l, int r, int val, int d)
{
  t[now = ++tcnt] = t[old];
  t[now].sum += d;
  if(l == r) return;
  int mid = (l + r) >> 1;
  if(val <= mid) insert(t[old].ls, t[now].ls, l, mid, val, d);
  else insert(t[old].rs, t[now].rs, mid + 1, r, val, d);
}
In ll query(int old, int now, int l, int r, int id)
{
  if(l == r) return t[now].sum - t[old].sum;
  int mid = (l + r) >> 1;
  if(id <= mid) return query(t[old].ls, t[now].ls, l, mid, id);
  else return t[t[now].ls].sum - t[t[old].ls].sum + query(t[old].rs, t[now].rs, mid + 1, r, id);
}

int dep[maxn], siz[maxn], dfn[maxn], pos[maxn], cnt = 0;
In void dfs(int now, int _f)
{
  siz[now] = 1;
  dfn[now] = ++cnt, pos[cnt] = now;
  for(int i = head[now], v; ~i; i = e[i].nxt)
    {
      if((v = e[i].to) == _f) continue;
      dep[v] = dep[now] + 1; 
      dfs(v, now);
      siz[now] += siz[v];
    }
}

int main()
{
  MYFILE();
  Mem(head, -1);
  n = read(), m = read();
  for(int i = 1; i < n; ++i)
    {
      int x = read(), y = read();
      addEdge(x, y), addEdge(y, x);
    }
  dfs(1, 0);
  for(int i = 1; i <= cnt; ++i) insert(root[i - 1], root[i], 1, n, dep[pos[i]], siz[pos[i]] - 1);
  for(int i = 1; i <= m; ++i)
    {
      int p = read(), K = read();
      ll ans = 1LL * (siz[p] - 1) * min(dep[p], K);
      ans += query(root[dfn[p]], root[dfn[p] + siz[p] - 1], 1, n, dep[p] + K);
      write(ans), enter;
    }
  return 0;
}
原文地址:https://www.cnblogs.com/mrclr/p/10976227.html