牛客练习赛67 F.牛妹的苹果树

题目链接

思路:考虑st表的思想。设 s t [ i ] [ j ] st[i][j] st[i][j]表示 [ i , i + 2 j ] [i,i+2^j] [i,i+2j]区间的点 构成的的树的直径的两个端点。转移就是从4个点选两个。就可以预处理出st数组。询问就是合并两个st的元素。
算是一类树上问题的技巧吧。学习到了。

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include 
using namespace std;
typedef long long LL;
const int N = 3e5 + 10;
#define fi first
#define se second
#define pb push_back
#define wzh(x) cerr<<#x<<'='<
int n,q;
vector<pair<int,int>>v[N];
int siz[N], fa[N], de[N], to[N], a[N], son[N];
int cnt;
LL s[N];
void dfs1(int now, int pre, int d) {
  siz[now] = 1;
  fa[now] = pre;
  de[now] = d;
  int cnt = -1;
  for (auto k : v[now]) {
    if (k.fi == pre)continue;
    s[k.fi]=s[now]+k.se;
    dfs1(k.fi, now, d + 1);
    siz[now] += siz[k.fi];
    if (siz[k.fi] > cnt) {
      cnt = siz[k.fi];
      son[now] = k.fi;
    }
  }
}
void dfs2(int now, int pre) {
  to[now] = pre;
  a[now] = ++cnt;
  if (!son[now])return ;
  dfs2(son[now], pre);
  for (auto k : v[now]) {
    if (k.fi == fa[now] || k.fi == son[now])continue;
    dfs2(k.fi, k.fi);
  }
}
int find_lca(int l, int r) {
 // cout<
  while (to[l] != to[r]) {
    if (de[to[l]] < de[to[r]])swap(l, r);
    l = fa[to[l]];
  }
  if (de[l] > de[r])swap(l, r);
//  cout<
  return l;
}
LL dis(int x,int y){
  return s[x]+s[y]-2*s[find_lca(x,y)];
}
pair<int,int> st[N][22];
int lg[N];
void gao() {
  lg[0] = -1;
  for (int i = 1; i < N; i++)
    lg[i] = lg[i >> 1] + 1;
  for(int i=1;i<=n;i++)st[i][0]={i,i};
  for (int j = 1; j < 20; j++) {
    for (int i = 1; i +(1<<j)-1<= n; i++) {
    //  st[i][0] = {i, i + 1}; //表示 [i,i+2^x] 区间 直径的两个端点
                             //    cout<
     // cout << i << ' ' << (i + (1 << j)) << endl;
      auto l = st[i][j - 1], r = st[i + (1 << j - 1)][j - 1];
      auto z = l;
      LL now=dis(l.fi,l.se);
      LL pre;
      if((pre=dis(r.fi,r.se))>now)z=r,now=pre;
      if(now<(pre=dis(l.fi,r.fi)))z={l.fi,r.fi},now=pre;
      if(now<(pre=dis(l.fi,r.se)))z={l.fi,r.se},now=pre;
      if(now<(pre=dis(r.fi,l.se)))z={r.fi,l.se},now=pre;
      if(now<(pre=dis(r.se,l.se)))z={r.se,l.se},now=pre;
      st[i][j] = z;
    }
  }
}
pair<int,int>merge(pair<int,int>l,pair<int,int>r){
  auto z=l;
//  cout<
  LL now=dis(l.fi,l.se);
  LL pre;
  if((pre=dis(r.fi,r.se))>now)z=r,now=pre;
  if(now<(pre=dis(l.fi,r.fi)))z={l.fi,r.fi},now=pre;
  if(now<(pre=dis(l.fi,r.se)))z={l.fi,r.se},now=pre;
  if(now<(pre=dis(r.fi,l.se)))z={r.fi,l.se},now=pre;
  if(now<(pre=dis(r.se,l.se)))z={r.se,l.se},now=pre;
  return z;
}
int main() {
  scanf("%d%d",&n,&q);
  for(int i=1;i<n;i++){
    int s,t,w;
    scanf("%d%d%d",&s,&t,&w);
    v[s].emplace_back(t,w);
    v[t].emplace_back(s,w);
  }
  //dis l r =d_l +d_r -2d_lca
  dfs1(1,0,0);
  dfs2(1,1);
  gao();
  for(int i=1;i<=q;i++){
    int l,r;
    scanf("%d%d",&l,&r);
    int k=lg[r-l+1];
    auto x=merge(st[l][k],st[r-(1<<k)+1][k]);
    printf("%lld\n",dis(x.fi,x.se));
//    cout<
  }
  return 0;
}

你可能感兴趣的:(st表)