lca问题
解决方法:树剖
思路:通过维护重儿子找出该节点的子节点中siz最大的那条链,然后再按照重链优先的顺序用线段树维护
先来一道最水的板子 P3379
#include <bits/stdc++.h>
#define new niuma
using namespace std;
int n;
const int maxn = 1e6 + 5;
int head[maxn];
int to[maxn];
int nxt[maxn];
int cnt;
int tp[maxn];
int dep[maxn];
int fa[maxn];
int new[maxn];
int timer;
int old[maxn];
int hson[maxn];
int siz[maxn];
void add(int x, int y) {
to[++cnt] = y;
nxt[cnt] = head[x];
head[x] = cnt;
}
void dfs1(int x, int f) {
dep[x] = dep[f] + 1;
fa[x] = f;
siz[x] = 1;
for (int i = head[x]; i; i = nxt[i]) {
int v = to[i];
if (v == f)
continue;
dfs1(v, x);
siz[x] += siz[v];
if (siz[v] > siz[hson[x]])
hson[x] = v;
}
}
void dfs2(int x, int top) {
tp[x] = top;
new[x] = ++timer;
old[new[x]] = x;
if (hson[x])
dfs2(hson[x], top);
for (int i = head[x]; i; i = nxt[i]) {
int v = to[i];
if (v == fa[x] || v == hson[x])
continue;
dfs2(v, v);
}
}
int ask(int x, int y) {
while (tp[x] != tp[y]) {
if (dep[tp[x]] < dep[tp[y]])
swap(x, y);
x = fa[tp[x]];
}
if (dep[x] > dep[y])
swap(x, y);
return x;
}
int m;
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n>>m;
int rt;
cin>>rt;
for (int i = 1; i < n; i++) {
int a, b;
cin >> a >> b;
add(a, b);
add(b, a);
}
dfs1(rt, 0);
dfs2(rt, rt);
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
cout << ask(x, y)<<'\n';
}
return 0;
}
运输计划
边转点,二分答案,树上查分维护每条路径能覆盖几个运输计划,check时枚举路径即可,要维护最长运输计划否则会tle(其实算一下也行,但是我懒)
#include <bits/stdc++.h>
#define new neww
#define int long long
using namespace std;
const int maxn = 6e5 + 5;
int top[maxn];
int new[maxn];
int old[maxn];
int hson[maxn];
int fa[maxn];
int dep[maxn];
int siz[maxn];
int timer;
int mk[maxn];
struct node {
int x, y, d;
} p[maxn];
int n, m;
int head[maxn];
int nxt[maxn];
int to[maxn];
int a[maxn];
int w[maxn];
int cnt;
void add(int x, int y, int z) {
to[++cnt] = y;
nxt[cnt] = head[x];
w[cnt] = z;
head[x] = cnt;
}
void dfs1(int x, int f) {
fa[x] = f;
siz[x] = 1;
for (int i = head[x]; i; i = nxt[i]) {
int v = to[i];
if (v == f)
continue;
a[v] = w[i];
dep[v] = dep[x] + w[i];
dfs1(v, x);
siz[x] += siz[v];
if (siz[v] > siz[hson[x]])
hson[x] = v;
}
}
void dfs2(int x, int tp) {
new[x] = ++timer;
old[new[x]] = x;
top[x] = tp;
if (hson[x])
dfs2(hson[x], tp);
for (int i = head[x]; i; i = nxt[i]) {
int v = to[i];
if (v == fa[x] || v == hson[x])
continue;
dfs2(v, v);
}
}
int query(int x, int y) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]])
swap(x, y);
x = fa[top[x]];
}
if (dep[x] > dep[y])
swap(x, y);
return x;
}
int tot;
void dfs(int x, int f) {
for (int i = head[x]; i; i = nxt[i]) {
if (to[i] == f)
continue;
int v = to[i];
dfs(v, x);
mk[x] += mk[v];
}
}
int dis(int x, int y) { return dep[x] + dep[y] - 2 * dep[query(x, y)]; }
int maxx = 0;
bool check(int x) {
for(int i=1;i<=n;i=-~i) mk[i]=0;
tot = 0;
for (int i = 1; i <= m; i = -~i) {
if (p[i].d > x) {
mk[p[i].x]++;
mk[p[i].y]++;
mk[query(p[i].x, p[i].y)] -= 2;
tot=-~tot;
}
}
dfs(1, 0);
for (int i = 1; i <= n; i = -~i) {
if (maxx - a[i] <= x && mk[i] == tot)
return 1;
}
return 0;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 1; i < n; i = -~i) {
int aa, b, t;
cin >> aa >> b >> t;
add(aa, b, t);
add(b, aa, t);
}
dfs1(1, 0);
dfs2(1, 1);
for (int i = 1; i <= m; i = -~i) {
int x, y;
cin >> x >> y;
p[i].x = x, p[i].y = y, p[i].d = dis(x, y);
maxx = max(p[i].d, maxx);
}
int l = 0, r = maxx;
while (l <= r) {
int mid = l + r >> 1;
if (check(mid))
r = mid - 1;
else
l = -~mid;
}
cout << l;
return 0;
}
严格次小生成树
枚举每条不在最小生成树的边,维护链上最大值次打值(千万别开俩线段树否则直接T飞)
#include<bits/stdc++.h>
#define int long long
#define new niumaa
#define mid (l+r>>1)
#define ls (k<<1)
#define rs (k<<1|1)
using namespace std;
const int maxn=6e5+5;
int new[maxn];
int dep[maxn];
int fa[maxn];
int tp[maxn];
int siz[maxn];
int hson[maxn];
int res1,res2;
int timer;
int head[maxn];
int to[maxn];
int nxt[maxn];
int w[maxn];
int a[maxn];
int maxx[maxn];
int sec[maxn];
int tot;
int n,m;
struct node{
int x,y,val;
bool is;
friend bool operator < (node a,node b){
return a.val<b.val;
}
}p[maxn];
int ff[maxn];
inline int find(int x){
return ff[x]==x?x:ff[x]=find(ff[x]);
}
//char buf[1<<24] , *p1 , *p2;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
#define getchar() cin.get()
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int cnt;
inline void add(int x,int y,int z){
to[++cnt]=y;
nxt[cnt]=head[x];
w[cnt]=z;
head[x]=cnt;
}
int old[maxn];
void dfs1(int x,int f){
fa[x]=f;
dep[x]=dep[f]+1;
siz[x]=1;
for(int i=head[x];i;i=nxt[i]){
int v=to[i];
if(v==f) continue;
a[v]=w[i];
dfs1(v,x);
siz[x]+=siz[v];
if(siz[v]>siz[hson[x]]){
hson[x]=v;
}
}
}
void dfs2(int x,int top){
new[x]=++timer;
old[new[x]]=x;
tp[x]=top;
if(hson[x]) dfs2(hson[x],top);
for(int i=head[x];i;i=nxt[i]){
int v=to[i];
if(v==fa[x]||v==hson[x]) continue;
dfs2(v,v);
}
}
int cal(int k,int l,int r){
if(maxx[ls]==maxx[rs]){
sec[k]=max(sec[ls],sec[rs]);
}
else{
sec[k]=max(sec[rs],min(maxx[rs],maxx[ls]));
}
return sec[k];
}
void build(int k,int l,int r){
if(l==r){
maxx[k]=a[old[l]];
sec[k]=0;
return;
}
build(ls,l,mid);
build(rs,mid+1,r);
maxx[k]=max(maxx[ls],maxx[rs]);
sec[k]=cal(k,l,r);
// cout<<l<<" "<<r<<" "<<maxx[ls]<<" "<<maxx[rs]<<" "<<old[l]<<" "<<old[r]<<" "<<maxx[k]<<" "<<sec[k]<<'\n';
}
int ask1(int k,int l,int r,int x,int y){
int ma=0;
if(y<x) return 0;
if(x<=l&&r<=y){
return maxx[k];
}
if(x<=mid){
ma=max(ma,ask1(ls,l,mid,x,y));
}
if(y>mid){
ma=max(ma,ask1(rs,mid+1,r,x,y));
}
return ma;
}
struct node2{
int maa,see;
}gan;
node2 ask2(int k,int l,int r,int x,int y){
bool flg=0;
node2 niuma;
int maxx1=0,maxx2=0;
if(x>y) return node2{0,0};
int se=0;
if(x<=l&&r<=y){
niuma.maa=maxx[k];
niuma.see=sec[k];
return niuma;
}
if(x<=mid){
node2 kkk=ask2(ls,l,mid,x,y);
maxx1=kkk.maa;
se=max(se,kkk.see);
}
if(y>mid){
node2 kkk=ask2(rs,mid+1,r,x,y);
maxx2=kkk.maa;
se=max(se,kkk.see);
}
if(maxx1!=0&&maxx2!=0&&maxx1!=maxx2){
se=max(min(maxx1,maxx2),se);
}
niuma.maa=max(maxx1,maxx2);
niuma.see=se;
return niuma;
}
void qry(int x,int y){
res1=0,res2=0;
while(tp[x]!=tp[y]){
if(dep[tp[x]]<dep[tp[y]]){
swap(x,y);
}
bool flag=0;
// return;
node2 wo=ask2(1,1,n,new[tp[x]],new[x]);
int now=wo.maa;
int lst=res1;
res1=max(now,res1);
if(lst!=now) flag=1;
if(flag) res2=max(res2,max(min(now,lst),wo.see));
else res2=max(res2,wo.see);
x=fa[tp[x]];
}
if(dep[x]>dep[y]) swap(x,y);
bool flag=0;
// return;
node2 wo=ask2(1,1,n,new[x]+1,new[y]);
int now=wo.maa;
int lst=res1;
res1=max(now,res1);
if(lst!=now) flag=1;
if(flag) res2=max(res2,max(min(now,lst),wo.see));
else res2=max(res2,wo.see);
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
n=read();
m=read();
for(int i=1;i<=n;i=-~i) ff[i]=i;
for(int i=1;i<=m;i=-~i){
int x,y,z;
x=read();
y=read();
z=read();
p[i].x=x;
p[i].y=y;
p[i].val=z;
}
sort(p+1,p+1+m);
for(int i=1;i<=m;i++){
int ax=find(p[i].x);
int bx=find(p[i].y);
if(ax==bx) continue;
p[i].is=1;
tot+=p[i].val;
add(p[i].x,p[i].y,p[i].val);
add(p[i].y,p[i].x,p[i].val);
ff[ax]=bx;
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
int ansss=1e18;
for(int i=1;i<=m;i=-~i){
if(p[i].is) continue;
if(p[i].x==p[i].y) continue;
qry(p[i].x,p[i].y);
if(p[i].val!=res1) ansss=min(ansss,tot-res1+p[i].val);
else ansss=min(ansss,tot-res2+p[i].val);
}
cout<<ansss;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话