luogu P5236 【模板】静态仙人掌

题面传送门
一道圆方树的板子题。
对于每个点先让它连到环顶。
那么他到环顶的距离就是从两边走的最小值。
那么求两点间距离就可以考虑倍增了。
但是最后要考虑特殊情况
代码实现:

#include<cstdio>
#include<cstring>
#define abs(x) ((x)>0?(x):-(x))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,xs,y,z,fa[10039][20],lg[10039],d[10039],now,cur,tot,ans[10039],vis[10039],st[10039],sh,f1[10039],f2[10039],flag[10039],nows[10039],nh;
long long sum[10039][20];
struct yyy{int to,w,z;}tmp;
struct ljb{
	int head,h[10039];
	yyy f[40039];
	inline void add(int x,int y,int z){
		f[++head]=(yyy){y,z,h[x]};
		h[x]=head;
	}
}s,c;
inline void dfs(int x,int last){
	int cur=s.h[x];
	yyy tmp;
	st[++sh]=x;vis[x]=1;
	while(cur!=-1){
		tmp=s.f[cur];
		if(tmp.to!=last){
		    if(vis[tmp.to]){
		    	if(!ans[tmp.to]){
		    		tot++;nh=0;
			        while(st[sh]!=tmp.to&&sh){
			        	c.add(tmp.to,st[sh],0);
			        	//printf("%d %d\n",tmp.to,st[sh]);
			        	ans[st[sh]]=tot;
			        	if(st[sh]==x)f1[x]=tmp.w;
			        	else f1[st[sh]]+=f1[st[sh+1]];
			        	nows[++nh]=st[sh];
			        	sh--;
			        }
			        nh--;
			        while(nh){
				        f2[nows[nh]]+=f2[nows[nh+1]];
			        	nh--;
		    	    }
				}
		    }
		    else{
		    	if(!ans[x]) f1[x]=tmp.w;
		    	f2[tmp.to]=tmp.w;
		    	dfs(tmp.to,x);
		    }
		}
		cur=tmp.z;
	}
	if(!ans[x]) sh--,f1[x]=f2[x],c.add(last,x,0)/*,printf("%d %d\n",last,x)*/;
}
inline void dfss(int x,int last){
	fa[x][0]=last;sum[x][0]=min(f1[x],f2[x]);
	d[x]=d[last]+1;
	for(int k=1;k<=lg[d[x]];k++)sum[x][k]=sum[fa[x][k-1]][k-1]+sum[x][k-1],fa[x][k]=fa[fa[x][k-1]][k-1];
	int cur=c.h[x];
	yyy tmp;
	while(cur!=-1){
		tmp=c.f[cur];
		if(tmp.to!=last) dfss(tmp.to,x);
		cur=tmp.z;
	}
}
inline void swap(int &x,int &y){x^=y,y^=x,x^=y;}
inline long long lca(int x,int y){
	long long anss=0;
	if(d[x]<d[y]) swap(x,y);
	while(d[x]>d[y]) anss+=sum[x][lg[d[x]-d[y]]-1],x=fa[x][lg[d[x]-d[y]]-1];
	if(x==y)return anss;
	for(int k=lg[d[x]];k>=0;k--) if(fa[x][k]!=fa[y][k]) anss+=sum[x][k]+sum[y][k],x=fa[x][k],y=fa[y][k];
	//printf("%d %d %d\n",x,y,anss);
	if(ans[x]==ans[y]&&ans[x]) return anss+min(abs(f1[x]-f1[y]),min(f1[x]+f2[y],f2[x]+f1[y]));
	else return anss+sum[x][0]+sum[y][0];
}
int main(){
//	freopen("1.in","r",stdin);
//	freopen("1.out","w",stdout);
	memset(s.h,-1,sizeof(s.h));
	memset(c.h,-1,sizeof(c.h));
	register int i;
	scanf("%d%d%d",&n,&m,&k);
	for(i=1;i<=n;i++)lg[i]=lg[i-1]+(1<<lg[i-1]==i);
	for(i=1;i<=m;i++) scanf("%d%d%d",&xs,&y,&z),s.add(xs,y,z),s.add(y,xs,z);
	dfs(1,0);
	//for(i=1;i<=n;i++) printf("%d %d\n",f1[i],f2[i]);
	dfss(1,0);
	for(i=1;i<=k;i++) scanf("%d%d",&xs,&y),printf("%lld\n",lca(xs,y));
}
基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip 个人大四的毕业设计、课程设计、作业、经导师指导并认可通过的高分设计项目,评审平均分达96.5分。主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。 [资源说明] 不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的毕设或者课设、作业,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96.5分,放心下载使用! 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),供学习参考。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值