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;
}

posted @   jt0007  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示