当前位置: 首页 > news >正文

2025年北京市大学生程序设计竞赛暨“小米杯”全国邀请赛——D

传送门:https://codeforces.com/gym/105851

题目大意:给定两个树S,T询问有多少点对(x,y) 在两棵树上的 LCA 相同
考虑在S树上进行树上启发式合并,大的集合叫 LLL, 小的叫RRR ,以TTT 树的dfn序为下标维护树状数组, 对于 x∈Rx \in RxR ,首先在 SSS 树上包含xxx 的那个集合的其它点和 xxx 都不会产生贡献,因为他们的LCA 最高也只是我当前合并的那棵子树根节点 rtrtrt 的儿子,考虑怎么计算,首先我们要预处理出每个节点为根在树状数组的范围([li,ri][l_i,r_i][li,ri]),然后我们把已经合并好的大集合都加到树状数组中,答案就加上 query([lrt,rrt])−query([ly,ry])query([l_{rt},r_{rt}])-query([l_y,r_y])query([lrt,rrt])query([ly,ry]) , yyy 就是上述包含 xxx 子树的深度最浅的节点( rtrtrt 的儿子),额外的加上 (x,y)(x,y)(x,y) 有一个点 rtrtrt 的贡献

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using i128 = __int128;//第一颗树启发式合并,在第二棵树的范围内,统计每个根节点和要加入的轻儿子产生的贡献
inline int lowbit(int x){return x&-x;
}
int n;
struct BIT{vector<int> tree;void init(int &n){tree.assign(n*2+10,0);}void add(int x,int v){for(x;x<tree.size();x+=lowbit(x)) tree[x]+=v;}int query(int x){int ans =0;for(x;x>0;x-=lowbit(x)) ans+=tree[x];return ans;}int ask(int l,int r){return query(r)-query(l-1);}
}tr;constexpr int maxn = 2e5+10;
vector<int> g1[maxn],g2[maxn];
int dfn[maxn],l[maxn],r[maxn],idx =0;
int f[maxn][20],dep[maxn];void update(){for(int j = 1;j<20;++j){for(int i = 1;i<=n;++i){f[i][j] = f[f[i][j-1]][j-1];}}
}
int jump(int x,int h){for(int i = 0;i<20;++i) if((h>>i)&1) x = f[x][i];return x;
}void dfs(int x,int fa){l[x]= dfn[x] = ++idx;dep[x] = dep[fa]+1;f[x][0]=fa;for(auto y:g2[x]){if(y==fa) continue;dfs(y,x);l[x] = min(l[x],l[y]);r[x] = max(r[x],r[y]);}r[x] = max(r[x],dfn[x]);}i64 ans=0;
int sz[maxn],son[maxn],HH;
void dfs1(int x,int fa){sz[x] = 1;for(auto &y:g1[x]){if(y==fa) continue;dfs1(y,x);sz[x]+=sz[y];if(sz[y]>sz[son[x]]) son[x]=y;}
}void deal(int x,int fa,int val){tr.add(dfn[x],val);for(auto &y:g1[x]){if(y==fa) continue;deal(y,x,val);}
}void calc(int x,int fa,int rt){if(l[rt]<=l[x]&&r[x]<=r[rt]){int bk = jump(x,dep[x]-dep[rt]-1);//第一棵树包含x的rt的childans+=tr.ask(l[rt],r[rt])-tr.ask(l[bk],r[bk]);}for(auto y:g1[x]){if(y==fa) continue;calc(y,x,rt);}
}void dsu(int x,int fa,int op){for(auto y:g1[x]){if(y==fa||y==son[x]) continue;dsu(y,x,0);}if(son[x]) dsu(son[x],x,1);ans+=tr.ask(l[x],r[x]);//rt=x的贡献tr.add(dfn[x],1);for(auto &y:g1[x]){if(y==fa||y==son[x]) continue;calc(y,x,x);deal(y,x,1);}if(!op) deal(x,fa,-1);
}void solve(){cin>>n;tr.init(n);idx = 0;for(int i = 0;i<=n;++i){l[i]=r[i]=dfn[i]=0;son[i]=0;g1[i].clear();g2[i].clear();}for(int i = 0;i<n-1;++i){int u,v;cin>>u>>v;g1[u].emplace_back(v);g1[v].emplace_back(u);}for(int i = 0;i<n-1;++i){int u,v;cin>>u>>v;g2[u].emplace_back(v);g2[v].emplace_back(u);}dfs(1,0);dfs1(1,0);update();ans =0;dsu(1,0,1);cout<<ans<<"\n";
}signed main(){ios::sync_with_stdio(0);cin.tie(0);int t=1;cin>>t;while(t--) solve();return 0;
}
http://www.lryc.cn/news/588125.html

相关文章:

  • 【从语言幻觉看趋势】从语言幻觉到多智能体协作:GPT多角色系统的技术演进与实践路径
  • MFC UI大小改变与自适应
  • MFC扩展库BCGControlBar Pro v36.2新版亮点:可视化设计器升级
  • Java集合和字符串
  • 如何通过API查询实时能源期货价格
  • 【机器学习深度学习】Ollama vs vLLM vs LMDeploy:三大本地部署框架深度对比解析
  • Function-——函数中文翻译渊源及历史背景
  • 重复频率较高的广告为何一直在被使用?
  • Three.js搭建小米SU7三维汽车实战(5)su7登场
  • 【世纪龙科技】汽车整车检测与诊断仿真实训系统-迈腾B8
  • Netty编程模型介绍
  • Olingo分析和实践——整体架构流程
  • 如何保护文件传输安全?文件传输加密
  • Mac下载mysql
  • 安装Keycloak并启动服务(macOS)
  • 概率论与数理统计(二)
  • 微信小程序——配置路径别名和省略后缀
  • 创客匠人:创始人 IP 打造的内核,藏在有效的精神成长里
  • 【第一章编辑器开发基础第一节绘制编辑器元素_6滑动条控件(6/7)】
  • 【PTA数据结构 | C语言版】字符串连接操作
  • Git安装避坑指南
  • 【Vue】Vue3.6 - Vapor 无虚拟DOM
  • 【第一章编辑器开发基础第二节编辑器布局_1水平与垂直布局(1/4)】
  • 计算两个经纬度之间的距离(JavaScript 实现)
  • 当 `conda list` 里出现两个 pip:一步步拆解并卸载冲突包
  • 详解BIO,NIO,AIO
  • Python Web框架对比:Flask vs FastAPI
  • Python数据容器-字典dict
  • 丑团-h5-Mtgsig算法-分析
  • Linux基础开发工具(3)