2018-2019 ACM-ICPC, Asia Dhaka Regional Contest F - Path Intersection 树上路径交

题目链接

思路:直接上树上路径交的模板。
或者树剖+线段树

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define wzh(x) cerr<<#x<<'='<<x<<endl;
int t,n;
struct tree {
  vector<int>v[N], g[N];
  int dep[N], f[N][22],tin[N],tout[N];
  int n, dfn[N], CNT,r;
  void init(int _n, int _r) {
    n = _n; r = _r; CNT = 0;
    for (int i = 1; i <= n; i++) {
      v[i].clear();
      g[i].clear();
    }
  }
  int lca(int u, int v) {
    if (dep[u] < dep[v])swap(u, v);
    for (int i = 16; i >= 0; i--)if ((dep[u] - dep[v]) >> i & 1)u = f[u][i];
    if (u == v)return u;
    for (int i = 16; i >= 0; i--)if (f[u][i] != f[v][i])u = f[u][i], v = f[v][i];
    return f[u][0];
  }
  void dfs(int x, int y) {
    f[x][0] = y; dfn[x] = ++CNT;
    dep[x] = dep[y] + 1;
    tin[x]=++CNT;
    for (int j = 1; j <= 16; j++) {
      f[x][j] = f[f[x][j - 1]][j - 1];
    }
    for (auto k : v[x])if (k != y) {
        dfs(k, x);
      }
    tout[x]=CNT;
  }
  int is_parent(int par,int v){
    return tin[par] <= tin[v] && tout[v] <= tout[par];
  }
  int dis(int x, int y) {
    return dep[x] + dep[y] - 2 * dep[lca(x, y)];
  }
  pair<int,int> intersect (int a1, int b1, int a2, int b2) {
    if (a1 == -1 || a2 == -1) {
      return make_pair(-1, -1);
    }
    int lca1 = lca(a1, b1);
    int lca2 = lca(a2, b2);
    vector<int> nodes = {a1, b1, a2, b2, lca1, lca2, lca(a1, a2), lca(a1, b2), lca(b1, a2), lca(b1, b2)};
    sort(nodes.begin(), nodes.end());
    nodes.erase(unique(nodes.begin(), nodes.end()), nodes.end());
    int best = -1e9;
    pair<int,int> ret = {-1, -1};

    auto is_ok = [&](int v) {
      return (is_parent(v, a1) || is_parent(v, b1)) && is_parent(lca1, v) && (is_parent(v, a2) || is_parent(v, b2)) && is_parent(lca2, v);
    };
    int sz=(int)nodes.size();
    for (int i = 0; i < sz; ++i) {
      for (int j = i; j < sz; ++j) {
        if (is_ok(nodes[i]) && is_ok(nodes[j])) {
          int val = dis(nodes[i], nodes[j]);
          if (val > best) {
            best = val;
            ret = {nodes[i], nodes[j]};
          }
        }
      }
    }
    return ret;
  }
} G;
int cas;
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  for(cin>>t,cas=1;cas<=t;cas++){
    cin>>n;G.init(n,1);
    for(int i=1;i<n;i++){
      int s,t;
      cin>>s>>t;
      G.v[s].pb(t);
      G.v[t].pb(s);
    }
    G.dfs(1,0);
    int Q;
    cin>>Q;
    cout<<"Case "<<cas<<":\n";
    for(int i=1;i<=Q;i++){
      int k;
      cin>>k;
      int x=-1,y=-1,che=1;
      for(int j=1;j<=k;j++){
        int l,r;
        cin>>l>>r;
        if(x==-1)x=l,y=r;
        else{
          auto z=G.intersect(x,y,l,r);
          x=z.fi;y=z.se;
        }
      }
      if(x==-1)cout<<0<<'\n';
      else cout<<G.dis(x,y)+1<<'\n';
    }
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值