树剖做法,10分求调
查看原帖
树剖做法,10分求调
697299
hamster000楼主2024/9/6 01:17
//思路:二分答案,check时把所有大于mid的路径利用树上差分覆盖一下
//如果没有被所有路径覆盖的边return false
//如果这样的边被剪去了仍然大于mid return false
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
inline int read(){
	int x=0,f=1;
	char c=getchar();
	while(!isdigit(c)){
		if(c=='-')f=-1;
		c=getchar();
	}
	while(isdigit(c)){
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
}

void write(int x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10+'0');
	return ;
}
const int maxn=3e5+10;

int top[maxn],fa[maxn];
struct edge{
	int to,w;
};
struct Seg1node{
	int val,l,r;
};
struct Seg1{//单点修改,查询区间和
	Seg1node tr[maxn<<2];
	int a[maxn];
	void init(){
		memset(a,0,sizeof a);
	}
	void pushup(int rt){
		tr[rt].val=tr[rt*2].val+tr[rt*2+1].val;
	}
	void build(int rt,int l,int r){
		tr[rt].l=l,tr[rt].r=r;
		if(l==r) {
			tr[rt].val=a[l];
			return;
		}
		int mid=(l+r)>>1;
		build(rt*2,l,mid),build(rt*2+1,mid+1,r);
		pushup(rt);
	}
	void modify(int rt,int pos,int x){
		int l=tr[rt].l,r=tr[rt].r;
		//cout << l << ' ' << r << endl;
		if(l==r){
			tr[rt].val+=x;
			return ;
		}
		int mid=(l+r)>>1;
		if(pos<=mid) modify(rt*2,pos,x);
		else modify(rt*2+1,pos,x);
		pushup(rt);
		return ;
	}
	int query(int rt,int x,int y){
		int l=tr[rt].l,r=tr[rt].r;
		//cout << l << ' ' << r << endl;
		//if(l==1&&r==3) return 0;
		if(x<=l&&r<=y){
			return tr[rt].val;
		}
		int mid=(l+r)>>1;
		int ans=0;
		if(x<=mid) ans+=query(rt*2,x,y);
		if(y>mid) ans+=query(rt*2+1,x,y);
		return ans;
	}
}seg1;

vector<edge> tree[maxn];
int dep[maxn],siz[maxn],son[maxn],val[maxn];
int dfn[maxn],cnt;
void dfs1(int u,int f,int v){
	fa[u]=f;dep[u]=dep[f]+1,siz[u]=1;
	val[u]=v;//连父亲方向的边权化为点权。
	
	for(auto v:tree[u]){
		int k=v.to;
		if(k==fa[u]) continue;
		dfs1(k,u,v.w);
		siz[u]+=siz[k];
		if(siz[k]>siz[son[u]]) son[u]=k;
	}
}

void dfs2(int u,int tp){
	top[u]=tp,dfn[u]=++cnt;
	if(!son[u]) return ;
	dfs2(son[u],tp);
	for(auto v:tree[u]){
		int k=v.to;
		if(k==fa[u]||k==son[u]) continue;
		dfs2(k,k);
	}
}

int lca(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]) return x;
	return y;
}

int getlength(int x,int y){
	int ans=0;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]){
			swap(x,y);
		}
		ans+=seg1.query(1,dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	if(x!=y) ans+=seg1.query(1,dfn[x]+1,dfn[y]);
	return ans;
}

int num[maxn];

void Run(int x,int y){//链加,但不加lca
	int LCA=lca(x,y);
	num[LCA]-=2;
	num[x]++;
	num[y]++;
}
void dfs3(int u){
	for(auto to:tree[u]){
		if(to.to==fa[u]) continue;
		dfs3(to.to);
		num[u]+=num[to.to];
	}
}
struct linker{
	int x,y,LCA,DIS;
}L[maxn];

bool check(int mid){
	int cnt=0,ans=0;
	memset(num,0,sizeof num);
	for(int i=1;i<=m;i++){
		if(L[i].DIS>mid){
			Run(L[i].x,L[i].y);
			ans=max(ans,L[i].DIS-mid);
			cnt++;
		}
	}
	//cout << cnt << endl;
	if(!cnt) return 1;
	dfs3(1);
	for(int i=2;i<=n;i++){
		if(num[i]==cnt&&seg1.query(1,dfn[fa[i]],dfn[i])>=ans) return 1;
	}
	return 0;
	
}

signed main(){
	n=read(),m=read();
	for(int i=1;i<n;i++){
		int a=read(),b=read(),c=read();
		tree[a].push_back({b,c});
		tree[b].push_back({a,c});
	}
	dfs1(1,0,0);
	dfs2(1,1);
	for(int i=1;i<=n;i++){
		seg1.a[dfn[i]]=val[i];
	}
	seg1.build(1,1,n);
	for(int i=1;i<=m;i++){
		L[i].x=read(),L[i].y=read();
		L[i].DIS=getlength(L[i].x,L[i].y);
		L[i].LCA=lca(L[i].x,L[i].y);
		//cout << L[i].DIS << ' ' << L[i].LCA<< endl;
	}
	int l=0,r=1e9;
	int mid;
	while(l<r){
		mid=(l+r)/2;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	write(l);
}
2024/9/6 01:17
加载中...