day50-时中

T1 CF516D Drazil and Morning Exercise

  • 给定一棵 n 个点的树,边有边权。
  • 定义 (f_x = max_{i=1}^n ext{dist}(x,i))
  • q 次询问最大的满足 (max_{x in s} f_x - min_{x in s} f_x le l) 的连通块 s 包含的点数。
  • (n le 10^5,q le 50)

solution

首先,两边dfs求出对于每个点的 (f_x) ,然后考虑以直径的中点作为根,那么在这个新的树里面,父亲的(f) 就会$ le $ 儿子的(f) ,满足一种单调性,于是用类似双指针的东西维护一遍即可。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
#define int long long
inline int read()
{
   register int x = 0 , f = 0; register char c = getchar();
   while(c < '0' || c > '9') f |= c == '-' , c = getchar();
   while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48) , c = getchar();
   return f ? -x : x;
}
int n;
int fa[N] , up[N] , f[N] , g[N] , p[N] , siz[N];
struct node { int v , c; node(int v = 0 , int c = 0) : v(v) , c(c) {} };
vector< node > G[N];

void dfs1(int x , int Fa)
{
   int tmp;
   for(auto w : G[x]) if(w.v != Fa)
   {
   	dfs1(w.v , x);
   	tmp = f[w.v] + w.c;
   	if(tmp > f[x]) g[x] = f[x] , f[x] = tmp;
   	else if(tmp > g[x]) g[x] = tmp;
   }
}

inline bool cmp(const int &A , const int &B) { return f[A] == f[B] ? A < B : f[A] < f[B]; }

void dfs2(int x , int Fa)
{
   int tmp;
   for(auto w : G[x]) if(w.v != Fa)
   {
   	tmp = w.c + ((f[w.v] + w.c == f[x]) ? g[x] : f[x]);
   	if(tmp > f[w.v]) g[w.v] = f[w.v] , f[w.v] = tmp;
   	else if(tmp > g[w.v]) g[w.v] = tmp;
   	dfs2(w.v , x);
   }
   for(auto w : G[x]) if(cmp(x , w.v)) up[w.v] = x; else up[x] = w.v;
}

int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }

void solve(int d)
{
   for(int i = 1 ; i <= n ; ++i) fa[i] = i , siz[i] = 1;
   int ans = 0;
   for(int i = n , j = n ; i >= 1 ; --i)
   {
   	while(f[p[j]] > f[p[i]] + d) --siz[find(p[j--])];
   	ans = max(ans , siz[p[i]]); siz[fa[p[i]] = up[p[i]]] += siz[p[i]];
   }
   cout << ans << '
';
}

signed main()
{
   n = read(); int u , v , c;
   for(int i = 1 ; i < n ; ++i)
   	u = read() , v = read() , c = read() , G[u].push_back(node(v , c)) , G[v].push_back(node(u , c));
   dfs1(1 , 0); dfs2(1 , 0);
   for(int i = 1 ; i <= n ; ++i) p[i] = i;
   sort(p + 1 , p + 1 + n , cmp);
   int Q = read(); while(Q--)  solve(read());
   return 0;
}
原文地址:https://www.cnblogs.com/R-Q-R-Q/p/13139752.html