求卡常,悬赏2关
查看原帖
求卡常,悬赏2关
580036
SnowTrace楼主2023/6/13 19:19

luogu本地可以过的,但是uoj机子巨慢,而且时限还开1s,过不了,有没有什么可以不把倍增改成树剖就能过的卡常方法?

#include<bits/stdc++.h>
using namespace std;
int n,m;
int lca[300005][20],d[300005],f[300005],ch[300005],res[300005][20];
vector<pair<int,int> >p[300005];
inline void dfs(int now,int fa,int ls){
	lca[now][0] = f[now] = fa;d[now] = d[fa]+1;res[now][0] = ls;
	for(int i = 1;i<18;i++)lca[now][i] = lca[lca[now][i-1]][i-1],res[now][i] = res[now][i-1]+res[lca[now][i-1]][i-1];
	for(int i =0 ;i<p[now].size();i++){
		if(p[now][i].first==fa)continue;
		dfs(p[now][i].first,now,p[now][i].second);
	}return;
}inline pair<int,int> lcaa(int x,int y){
	if(d[x]<d[y])swap(x,y);
	int dis = abs(d[x]-d[y]),sum =0 ;
	for(int i =0;i<18,dis;i++,dis>>=1){
		if(dis&1)sum+=res[x][i],x = lca[x][i];
	}if(x == y)return {x,sum};
	for(int i = 17;i>=0;i--){
		if(lca[x][i] != lca[y][i])sum+=res[x][i]+res[y][i],x = lca[x][i],y = lca[y][i];
	}return {lca[x][0],sum+res[x][0]+res[y][0]};
}inline pair<int,int> dis(int x,int y){
	int l = lcaa(x,y).first;
	int dis = abs(d[x]-d[l]);int ans =0;
	for(int i =0;i<17,dis;i++,dis>>=1)if(dis&1)ans+=res[x][i],x=  lca[x][i];
	dis = abs(d[y]-d[l]);
	for(int i =0;i<17,dis;i++,dis>>=1)if(dis&1)ans+=res[y][i],y=  lca[y][i];
	return {l,ans};
}
inline void dfs2(int now){
	for(int i =0;i<p[now].size();i++){
		if(p[now][i].first == f[now])continue;
		dfs2(p[now][i].first);
		ch[now]+=ch[p[now][i].first];
	}return;
}vector<pair<pair<int,int>,int> >edge;
int mx =0;
struct node{
	int x,y,l,sum;
};vector<node>query;
bool check(int x){
	//cout << x << endl;
	memset(ch,0,sizeof(ch));
	int tot = 0,c = 0;
	for(int i =0;i<query.size();i++){
		if(query[i].sum>x){
	//		cout << query[i].x << " " << query[i].y << " " << query[i].sum  << " " <<query[i].l<< endl;
			ch[query[i].x]+=1,ch[query[i].y]+=1;
			ch[query[i].l]-=2;
			c= max(c,query[i].sum);tot++;
		}
	}if(mx+x<c)return 0;
	//cout << tot << endl;
	//for(int i = 1;i<=n;i++)cout << ch[i] << " ";cout << endl;
	dfs2(1);
	//for(int i =1;i<=n;i++)cout << ch[i] << " ";cout << endl;
	for(int i =0;i<edge.size();i++){
		int xx = edge[i].first.first,y = edge[i].first.second;
		int p = xx;
		if(d[xx]<d[y])p= y;
		if(ch[p] == tot){
	//		cout << xx << " " << y << endl;
			if(edge[i].second>=c-x)return 1;
		}
	}return 0;
}
signed main(){
	std::ios::sync_with_stdio(false);
    std::cin.tie(0);
	cin >> n >> m;
	for(int i = 1;i<n;i++){
		int a,b,c;cin >> a >> b >> c;
		p[a].push_back({b,c}),p[b].push_back({a,c});
		edge.push_back({{a,b},c});mx=  max(mx,c);
	}dfs(1,1,0);
//	cout << 0<< endl;
	for(int i = 1;i<=m;i++){
		int a,b;cin >> a >> b;pair<int,int>e = lcaa(a,b);
		query.push_back((node){a,b,e.first,e.second});
	}int l = 0,r = 3e8;
	while(l<r){
		int mid = l+r>>1;
		if(check(mid))r = mid;
		else l = mid+1;
	}cout << l << '\n';
	return 0;
}

此处我省略了一个火车头。

2023/6/13 19:19
加载中...