【Learning】倍增求LCA题目汇总

这里是我倍增的练习记录,大多都是水题…也有一些混合了其它算法的。= = 顺序可能有些错乱,并不是按照难度来排的。
T1 hdu3710 倍增+树剖
这里写图片描述

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=20005,M=100005,inf=2139062143;
int t,n,m,u,v,d,f,ns,rt,cnt,idx,head[N],to[N*2],nxt[N*2];
int dep[N],fa[N][20],siz[N],son[N],dfn[N],pos[N],top[N];
int minn[N],minv[N*4],tag[N*4];
bool use[M];
int s,mst,smst,pa[N],w[N],sont[N],num[N];
struct edge{
	int u,v,d;
	bool operator < (const edge &x)const{
		return d<x.d;
	}
}e[M];
vector<edge> link[N],edges;
void init(){
	smst=idx=cnt=rt=0;
	memset(use,0,sizeof(use));
	memset(head,0,sizeof(head));
	memset(dep,0,sizeof(dep));
	memset(fa,0,sizeof(fa));
	memset(son,0,sizeof(son));
	memset(sont,0,sizeof(sont));
	memset(w,0,sizeof(w));
	memset(minv,127,sizeof(minv));
	memset(tag,127,sizeof(tag));
	for(int i=1;i<=n;i++){
		pa[i]=i;
		link[i].clear();
	}
}
void adde(int u,int v){
	to[++cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
}
int find(int u){
	return u==pa[u]?u:pa[u]=find(pa[u]);
}
void dfs(int u){
	for(int i=1;(1<<i)<=dep[u];i++){
		fa[u][i]=fa[fa[u][i-1]][i-1];
	}
	siz[u]=1;
	int v;
	for(int i=head[u];i;i=nxt[i]){
		v=to[i];
		if(v!=fa[u][0]){
			fa[v][0]=u;
			dep[v]=dep[u]+1;
			num[v]=++sont[u];
			dfs(v);
			siz[u]+=siz[v];
			if(!son[u]||siz[son[u]]<siz[v]){
				son[u]=v;
			}
		}
	}
}
void dfs(int u,int tp){
	dfn[u]=++idx;
	pos[idx]=u;
	top[u]=tp;
	if(son[u]){
		dfs(son[u],tp);
	}
	int v;
	for(int i=head[u];i;i=nxt[i]){
		v=to[i];
		if(v!=fa[u][0]&&v!=son[u]){
			dfs(v,v);
		}
	}
}
void pushdown(int o){
	minv[o*2]=min(minv[o*2],tag[o]);
	minv[o*2+1]=min(minv[o*2+1],tag[o]);
	tag[o*2]=min(tag[o*2],tag[o]);
	tag[o*2+1]=min(tag[o*2+1],tag[o]);
	tag[o]=inf;
}
void upd(int o,int l,int r,int L,int R,int x){
	if(L<=l&&R>=r){
		minv[o]=min(minv[o],x);
		tag[o]=min(tag[o],x);
		return;
	}
	if(tag[o]!=inf){
		pushdown(o);
	}
	int mid=(l+r)/2;
	if(L<=mid){
		upd(o*2,l,mid,L,R,x);
	}
	if(R>mid){
		upd(o*2+1,mid+1,r,L,R,x);
	}
	minv[o]=min(minv[o*2],minv[o*2+1]);
}
void update(int u,int v,int x){
	while(top[u]!=top[v]){
		upd(1,1,n,dfn[top[u]],dfn[u],x);
		u=fa[top[u]][0];
	}
	upd(1,1,n,dfn[v],dfn[u],x);
}
void getmin(int o,int l,int r){
	if(l==r){
		minn[pos[l]]=minv[o];
		return;
	}
	if(tag[o]!=inf){
		pushdown(o);
	}
	int mid=(l+r)/2;
	getmin(o*2,l,mid);
	getmin(o*2+1,mid+1,r);
}
void work(edge &e){
	int u=e.u,v=e.v,d;
	d=dep[u]-dep[v];
	for(int i=0;(1<<i)<=d;i++){
		if(d&(1<<i)){
			u=fa[u][i];
		}
	}
	if(u==v){
		u=e.u;
		d=dep[u]-dep[v]-2;
		if(d<0){
			return;
		}
		for(int i=0;(1<<i)<=d;i++){
			if(d&(1<<i)){
				u=fa[u][i];
			}
		}
		update(e.u,u,e.d);
		return;
	}
	int tmpu=u,tmpv=v;
	for(int i=15;i>=0;i--){
		if(fa[tmpu][i]!=fa[tmpv][i]){
			tmpu=fa[tmpu][i];
			tmpv=fa[tmpv][i];
		}
	}
	link[fa[tmpu][0]].push_back((edge){tmpu,tmpv,e.d});
	d=dep[e.u]-dep[tmpu]-1;
	if(d>=0){
		u=e.u;
		for(int i=0;(1<<i)<=d;i++){
			if(d&(1<<i)){
				u=fa[u][i];
			}
		}
		update(e.u,u,e.d);
	}
	d=dep[e.v]-dep[tmpv]-1;
	if(d>=0){
		v=e.v;
		for(int i=0;(1<<i)<=d;i++){
			if(d&(1<<i)){
				v=fa[v][i];
			}
		}
		update(e.v,v,e.d);
	}
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		init();
		for(int i=1;i<=m;i++){
			scanf("%d%d%d%d",&e[i].u,&e[i].v,&d,&f);
			e[i].d=d*(1-f);
		}
		sort(e+1,e+m+1);
		ns=0;
		for(int i=1;i<=m&&ns<n-1;i++){
			u=find(e[i].u),v=find(e[i].v);
			if(u!=v){
				use[i]=true;
				pa[v]=u;
				ns++;
				adde(e[i].u,e[i].v);
				adde(e[i].v,e[i].u);
				w[e[i].u]+=e[i].d;
				w[e[i].v]+=e[i].d;
				smst+=e[i].d;
				if(!rt){
					rt=e[i].u;
				}
			}
		}
		dfs(rt);
		dfs(rt,rt);
		for(int i=1;i<=m;i++){
			if(!use[i]){
				if(dep[e[i].u]<dep[e[i].v]){
					swap(e[i].u,e[i].v);
				}
				work(e[i]);
			}
		}
		getmin(1,1,n);
		for(int i=1;i<=n;i++){
			edges.clear();
			s=sont[i];
			if(fa[i][0]){
				s++;
				for(int j=head[i];j;j=nxt[j]){
					v=to[j];
					if(v!=fa[i][0]&&minn[v]!=inf){
						edges.push_back((edge){num[v],s,minn[v]});
					}
				}
			}
			for(int j=0;j<link[i].size();j++){
				edges.push_back((edge){num[link[i][j].u],num[link[i][j].v],link[i][j].d});
			}
			sort(edges.begin(),edges.end());
			mst=0;
			for(int j=1;j<=s;j++){
				pa[j]=j;
			}
			ns=0;
			for(int j=0;j<edges.size()&&ns<s-1;j++){
				u=find(edges[j].u),v=find(edges[j].v);
				if(u!=v){
					pa[v]=u;
					ns++;
					mst+=edges[j].d;
				}
			}
			if(ns<s-1){
				puts("inf");
			}else{
				printf("%d\n",smst-w[i]+mst);
			}
		}
	}
	return 0;
}

T2 luogu3379 模板题
这里写图片描述

#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,root,cnt,u,v,head[500005],to[1000005],nxt[1000005],dep[500005],fa[500005][21];
void adde(int u,int v){
	to[++cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
}
void dfs(int u){
	for(int i=1;(1<<i)<=dep[u];i++){
		fa[u][i]=fa[fa[u][i-1]][i-1];
	}
	int v;
	for(int i=head[u];i;i=nxt[i]){
		v=to[i];
		if(v!=fa[u][0]){
			fa[v][0]=u;
			dep[v]=dep[u]+1;
			dfs(v);
		}
	}
}
int lca(int u,int v){
	if(dep[u]<dep[v]){
		swap(u,v);
	}
	int d=dep[u]-dep[v];
	for(int i=0;(1<<i)<=d;i++){
		if(d&(1<<i)){
			u=fa[u][i];
		}
	}
	if(u==v){
		return u;
	}
	for(int i=20;i>=0;i--){
		if(fa[u][i]!=fa[v][i]){
			u=fa[u][i];
			v=fa[v][i];
		}
	}
	return fa[u][0];
}
int main(){
	scanf("%d%d%d",&n,&m,&root);
	for(int i=1;i<n;i++){
		scanf("%d%d",&u,&v);
		adde(u,v);
		adde(v,u);
	}
	dfs(root);
	while(m--){
		scanf("%d%d",&u,&v);
		printf("%d\n",lca(u,v));
	}
	return 0;
}

T3 zoj3195 模板题
这里写图片描述

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,q,cnt,u,v,d,head[50005],to[100005],nxt[100005],dep[50005],dis[50005],dd[100005],fa[50005][21];
bool flag=false; 
void adde(int u,int v,int d){
	to[++cnt]=v;
	nxt[cnt]=head[u];
	dd[cnt]=d;
	head[u]=cnt;
}
void dfs(int u){
	for(int i=1;(1<<i)<=dep[u];i++){
		fa[u][i]=fa[fa[u][i-1]][i-1];
	}
	int v;
	for(int i=head[u];i;i=nxt[i]){
		v=to[i];
		if(v!=fa[u][0]){
			fa[v][0]=u;
			dep[v]=dep[u]+1;
			dis[v]=dis[u]+dd[i];
			dfs(v);
		}
	}
}
int lca(int u,int v){
	if(dep[u]<dep[v]){
		swap(u,v);
	}
	int d=dep[u]-dep[v];
	for(int i=0;(1<<i)<=d;i++){
		if(d&(1<<i)){
			u=fa[u][i];
		}
	}
	if(u==v){
		return u;
	}
	for(int i=20;i>=0;i--){
		if(fa[u][i]!=fa[v][i]){
			u=fa[u][i];
			v=fa[v][i];
		}
	}
	return fa[u][0];
}
int main(){
	while(~scanf("%d",&n)){
		if(!flag){
			flag=true;
		}else{
			puts("");
		}
		cnt=0;
		memset(head,0,sizeof(head));
		memset(dep,0,sizeof(dep));
		memset(fa,0,sizeof(fa));
		memset(dis,0,sizeof(dis)); 
		for(int i=1;i<n;i++){
			scanf("%d%d%d",&u,&v,&d);
			u++,v++;
			adde(u,v,d);
			adde(v,u,d);
		}
		dfs(1);
		scanf("%d",&q);
		for(int i=1;i<=q;i++){
			scanf("%d%d%d",&u,&v,&d);
			u++,v++,d++;
			printf("%d\n",dis[u]+dis[v]+dis[d]-dis[lca(u,v)]-dis[lca(u,d)]-dis[lca(v,d)]);
		}
	}
	return 0;
}

T4 bzoj2588 主席树+树上差分+倍增lca
这里写图片描述

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int N=100005;
int n,m,x,y,k,lca,lastans=0,tot=0,cnt=0,a[N],head[N],nxt[N*2],to[N*2],root[N],dep[N],fa[N][20];
vector<int> v;
struct Node
{
	int l,r,sum;
	Node(){sum=0;}
}node[N*40];
int getId(int x)
{
	return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void adde(int u,int v)
{
	to[++tot]=v;
	nxt[tot]=head[u];
	head[u]=tot;
}
void update(int l,int r,int &x,int y,int pos)
{
	node[x=++cnt]=node[y];
	node[x].sum++;
	if(l==r) return;
	int mid=(l+r)/2;
	if(pos<=mid) update(l,mid,node[x].l,node[y].l,pos);
	else update(mid+1,r,node[x].r,node[y].r,pos);
}
int query(int l,int r,int a,int b,int c,int d,int k)
{
	if(l==r) return l;
	int mid=(l+r)/2,sum=node[node[a].l].sum+node[node[b].l].sum-node[node[c].l].sum-node[node[d].l].sum;
	if(k<=sum) return query(l,mid,node[a].l,node[b].l,node[c].l,node[d].l,k);
	else return query(mid+1,r,node[a].r,node[b].r,node[c].r,node[d].r,k-sum);
}
void dfs(int pre,int u,int d)
{
	fa[u][0]=pre;
	dep[u]=d;
	for(int i=1;(1<<i)<=d;i++)
		fa[u][i]=fa[fa[u][i-1]][i-1];
	update(1,n,root[u],root[pre],getId(a[u]));
	for(int i=head[u];i;i=nxt[i])
		if(to[i]^pre)
			dfs(u,to[i],d+1);
}
int LCA(int u,int v)
{
	if(dep[u]>dep[v]) swap(u,v);
	int d=dep[v]-dep[u];
	for(int i=0;(1<<i)<=d;i++)
		if((1<<i)&d) v=fa[v][i];
	if(u!=v)
	{
		for(int i=16;i>=0;i--)
			if(fa[u][i]!=fa[v][i])
			{
				u=fa[u][i];
				v=fa[v][i];
			}
		u=fa[u][0];
	}
	return u;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		v.push_back(a[i]);
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()),v.end());
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		adde(x,y);
		adde(y,x);
	}
	dfs(0,1,1);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&x,&y,&k);
		x^=lastans;
		lca=LCA(x,y);
		lastans=v[query(1,n,root[x],root[y],root[lca],root[fa[lca][0]],k)-1];
		printf("%d",lastans);
		if(i^m) putchar('\n');
	}
	return 0;
}

T5 bzoj1787&&bzoj1832 模版题
这里写图片描述
这里写图片描述

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int t,n,q,cnt,u,v,d,t1,t2,t3,p,head[500005],to[1000005],nxt[1000005],dep[500005],fa[500005][21];
void adde(int u,int v){
	to[++cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
}
void dfs(int u){
	for(int i=1;(1<<i)<=dep[u];i++){
		fa[u][i]=fa[fa[u][i-1]][i-1];
	}
	int v;
	for(int i=head[u];i;i=nxt[i]){
		v=to[i];
		if(v!=fa[u][0]){
			fa[v][0]=u;
			dep[v]=dep[u]+1;
			dfs(v);
		}
	}
}
int lca(int u,int v){
	if(dep[u]<dep[v]){
		swap(u,v);
	}
	int d=dep[u]-dep[v];
	for(int i=0;(1<<i)<=d;i++){
		if(d&(1<<i)){
			u=fa[u][i];
		}
	}
	if(u==v){
		return u;
	}
	for(int i=20;i>=0;i--){
		if(fa[u][i]!=fa[v][i]){
			u=fa[u][i];
			v=fa[v][i];
		}
	}
	return fa[u][0];
}
int dis(int u,int v){
	return dep[u]+dep[v]-2*dep[lca(u,v)]; 
}
int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<n;i++){
		scanf("%d%d",&u,&v);
		adde(u,v);
		adde(v,u);
	}
	dfs(1);
	for(int i=1;i<=q;i++){
		scanf("%d%d%d",&u,&v,&d);
		t1=lca(u,v),t2=lca(u,d),t3=lca(v,d);
		if(t1==t2){
			p=t3;
		}
		else if(t1==t3){
			p=t2;
		}
		else{
			p=t1;
		}
		printf("%d %d\n",p,dis(u,p)+dis(v,p)+dis(d,p));
	}
	return 0;
}

T6 hdu2586 模版题
这里写图片描述

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int t,n,q,cnt,u,v,d,head[40005],to[80005],nxt[80005],dep[40005],dis[40005],dd[800005],fa[40005][21];
void adde(int u,int v,int d){
	to[++cnt]=v;
	nxt[cnt]=head[u];
	dd[cnt]=d;
	head[u]=cnt;
}
void dfs(int u){
	for(int i=1;(1<<i)<=dep[u];i++){
		fa[u][i]=fa[fa[u][i-1]][i-1];
	}
	int v;
	for(int i=head[u];i;i=nxt[i]){
		v=to[i];
		if(v!=fa[u][0]){
			fa[v][0]=u;
			dep[v]=dep[u]+1;
			dis[v]=dis[u]+dd[i];
			dfs(v);
		}
	}
}
int lca(int u,int v){
	if(dep[u]<dep[v]){
		swap(u,v);
	}
	int d=dep[u]-dep[v];
	for(int i=0;(1<<i)<=d;i++){
		if(d&(1<<i)){
			u=fa[u][i];
		}
	}
	if(u==v){
		return u;
	}
	for(int i=20;i>=0;i--){
		if(fa[u][i]!=fa[v][i]){
			u=fa[u][i];
			v=fa[v][i];
		}
	}
	return fa[u][0];
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&q);
		cnt=0;
		memset(head,0,sizeof(head));
		memset(dep,0,sizeof(dep));
		memset(fa,0,sizeof(fa));
		memset(dis,0,sizeof(dis)); 
		for(int i=1;i<n;i++){
			scanf("%d%d%d",&u,&v,&d);
			adde(u,v,d);
			adde(v,u,d);
		}
		dfs(1);
		for(int i=1;i<=q;i++){
			scanf("%d%d",&u,&v);
			printf("%d\n",dis[u]+dis[v]-2*dis[lca(u,v)]);
		}
	}
	return 0;
}

T7 poj1330 模版题
这里写图片描述

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int t,n,cnt,u,v,head[10005],to[10005],nxt[10005],dep[10005],fa[10005][21];
bool ck[10005];
void adde(int u,int v){
	to[++cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
}
void dfs(int u){
	for(int i=1;(1<<i)<=dep[u];i++){
		fa[u][i]=fa[fa[u][i-1]][i-1];
	}
	int v;
	for(int i=head[u];i;i=nxt[i]){
		v=to[i];
		fa[v][0]=u;
		dep[v]=dep[u]+1;
		dfs(v);
	}
}
int lca(int u,int v){
	if(dep[u]<dep[v]){
		swap(u,v);
	}
	int d=dep[u]-dep[v];
	for(int i=0;(1<<i)<=d;i++){
		if(d&(1<<i)){
			u=fa[u][i];
		}
	}
	if(u==v){
		return u;
	}
	for(int i=20;i>=0;i--){
		if(fa[u][i]!=fa[v][i]){
			u=fa[u][i];
			v=fa[v][i];
		}
	}
	return fa[u][0];
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		cnt=0;
		memset(head,0,sizeof(head));
		memset(dep,0,sizeof(dep));
		memset(fa,0,sizeof(fa));
		memset(ck,0,sizeof(ck));
		for(int i=1;i<n;i++){
			scanf("%d%d",&u,&v);
			adde(u,v);
			ck[v]=true;
		}
		for(int i=1;i<=n;i++){
			if(!ck[i]){
				dfs(i);
				break;
			}
		}
		scanf("%d%d",&u,&v);
		printf("%d\n",lca(u,v));
	}
	return 0;
}

T8 gdgzoi2232祖孙询问 模版题
这里写图片描述

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int t,n,m,cnt,u,v,tmp,rt,head[40005],to[80005],nxt[80005],dep[40005],fa[40005][21];
void adde(int u,int v){
	to[++cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
}
void dfs(int u){
	for(int i=1;(1<<i)<=dep[u];i++){
		fa[u][i]=fa[fa[u][i-1]][i-1];
	}
	int v;
	for(int i=head[u];i;i=nxt[i]){
		v=to[i];
		if(v!=fa[u][0]){
			fa[v][0]=u;
			dep[v]=dep[u]+1;
			dfs(v);
		}
	}
}
int lca(int u,int v){
	if(dep[u]<dep[v]){
		swap(u,v);
	}
	int d=dep[u]-dep[v];
	for(int i=0;(1<<i)<=d;i++){
		if(d&(1<<i)){
			u=fa[u][i];
		}
	}
	if(u==v){
		return u;
	}
	for(int i=20;i>=0;i--){
		if(fa[u][i]!=fa[v][i]){
			u=fa[u][i];
			v=fa[v][i];
		}
	}
	return fa[u][0];
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&u,&v);
		if(~v){
			adde(u,v);
			adde(v,u);
		}
		else{
			rt=u;
		}
	}
	dfs(rt);
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&u,&v);
		tmp=lca(u,v);
		if(tmp==u){
			puts("1");
		}else if(tmp==v){
			puts("2");
		}else{
			puts("0");
		}
	}
	return 0;
}

这么多水题忽然好颓废啊!
T9 luogu1967&&xsy2018 倍增+最大生成树
这里写图片描述

#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,q,u,v,cnt,pa[10005],head[10005],to[20005],nxt[20005],dd[20005],fa[10005][20],minn[10005][20];
int dep[10005];
struct edge{
	int u,v,d;
}e[50005];
bool cmp(edge a,edge b){
	return a.d>b.d;
}
int find(int u){
	return u==pa[u]?u:pa[u]=find(pa[u]);
}
void adde(int u,int v,int d){
	to[++cnt]=v;
	nxt[cnt]=head[u];
	dd[cnt]=d;
	head[u]=cnt;
}
void dfs(int u){
	for(int i=1;(1<<i)<=dep[u];i++){
		fa[u][i]=fa[fa[u][i-1]][i-1];
		minn[u][i]=min(minn[u][i-1],minn[fa[u][i-1]][i-1]);
	}
	int v;
	for(int i=head[u];i;i=nxt[i]){
		v=to[i];
		if(v!=fa[u][0]){
			fa[v][0]=u;
			minn[v][0]=dd[i];
			dep[v]=dep[u]+1;
			dfs(v);
		}
	}
}
int solve(int u,int v){
	if(dep[u]<dep[v]){
		swap(u,v);
	}
	int ans=0x7fffffff,d=dep[u]-dep[v];
	for(int i=0;(1<<i)<=d;i++){
		if(d&(1<<i)){
			ans=min(ans,minn[u][i]);
			u=fa[u][i];
		}
	}
	if(u==v){
		return ans;
	}
	for(int i=16;i>=0;i--){
		if(fa[u][i]!=fa[v][i]){
			ans=min(ans,min(minn[u][i],minn[v][i]));
			u=fa[u][i];
			v=fa[v][i];
		}
	}
	if(fa[u][0]){
		return min(ans,min(minn[u][0],minn[v][0]));
	}else{
		return -1;
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		pa[i]=i;
	}
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].d);
	}
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=m;i++){
		u=find(e[i].u),v=find(e[i].v);
		if(u!=v){
			adde(e[i].u,e[i].v,e[i].d);
			adde(e[i].v,e[i].u,e[i].d);
			pa[v]=u;
		}
	}
	dfs(1);
	scanf("%d",&q);
	for(int i=1;i<=q;i++){
		scanf("%d%d",&u,&v);
		printf("%d\n",solve(u,v));
	}
	return 0;
}

T10 CF587C&&xsy2414 倍增+归并
这里写图片描述

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,q,u,v,t,tmp,cnt,ans[15],a[100005],head[100005],to[200005],nxt[200005],fa[100005][20],dep[100005],minn[100005][20][15];
void adde(int u,int v){
	to[++cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
}
void merge(int a[],int b[],int d[]){
	int i=1,j=1,k=0,c[15];
	while(i<=a[0]&&j<=b[0]&&k<10){
		if(a[i]<b[j]){
			c[++k]=a[i++];
		}else{
			c[++k]=b[j++];
		}
	}
	while(i<=a[0]&&k<10){
		c[++k]=a[i++];
	}
	while(j<=b[0]&&k<10){
		c[++k]=b[j++];
	}
	for(int i=1;i<=k;i++){
		d[i]=c[i];
	}
	d[0]=k;
}
void dfs(int u){
	memcpy(minn[u][1],minn[fa[u][1]][0],sizeof(minn[fa[u][1]][0]));
	for(int i=2;i<=17;i++){
		fa[u][i]=fa[fa[u][i-1]][i-1];
		merge(minn[u][i-1],minn[fa[u][i-1]][i-1],minn[u][i]);
	}
	int v;
	for(int i=head[u];i;i=nxt[i]){
		v=to[i];
		if(v!=fa[u][1]){
			fa[v][1]=u;
			dep[v]=dep[u]+1;
			dfs(v);
		}
	}
} 
void solve(int u,int v,int t){
	if(dep[u]<dep[v]){
		swap(u,v);
	}
	int d=dep[u]-dep[v];
	memcpy(ans,minn[u][0],sizeof(minn[u][0]));
	for(int i=1;i<=17;i++){
		if(d&(1<<(i-1))){
			merge(ans,minn[u][i],ans);
			u=fa[u][i];
		}
	}
	if(u!=v){
		merge(ans,minn[v][0],ans);
		for(int i=17;i>=1;i--){
			if(fa[u][i]!=fa[v][i]){
				merge(ans,minn[u][i],ans);
				merge(ans,minn[v][i],ans);
				u=fa[u][i];
				v=fa[v][i];
			}
		}
		merge(ans,minn[u][1],ans);
	}
	ans[0]=min(ans[0],t);
	printf("%d ",ans[0]);
	for(int i=1;i<=ans[0];i++){
		printf("%d ",ans[i]);
	}
	puts("");
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<n;i++){
		scanf("%d%d",&u,&v);
		adde(u,v);
		adde(v,u);
	}
	for(int i=1;i<=m;i++){
		scanf("%d",&tmp);
		minn[tmp][0][++minn[tmp][0][0]]=i;
	}
	dfs(1);
	for(int i=1;i<=q;i++){
		scanf("%d%d%d",&u,&v,&t);
		solve(u,v,t);
	}
	return 0;
}

T11 bzoj3545&&bzoj3551 并查集+谜之建树+倍增+线段树
UPD 2020.11.9:这是Kruskal重构树。
这里写图片描述
这里写图片描述

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
inline int rd()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int N=100005;
int n,m,q,tot,cnt,idx,h[N],pa[2*N],val[2*N],head[N*2],to[N*2],nxt[N*2],dep[N*2],fa[N*2][20],mx[N*2][20];
int lc[50*N],rc[50*N],sumv[50*N],pos[N*3],root[N*3],bg[N*2],ed[N*2];
bool vis[N*2];
vector<int> V;
struct edge
{
	int u,v,d;
}a[5*N];
bool cmp(edge a,edge b)
{
	return a.d<b.d;
}
int findrt(int u)
{
	return u==pa[u]?u:pa[u]=findrt(pa[u]);
}
void adde(int u,int v)
{
	to[++cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
}
void dfs(int u)
{
	vis[u]=true;
	pos[++pos[0]]=u;
	for(int i=1;(1<<i)<=dep[u];i++)
	{
		fa[u][i]=fa[fa[u][i-1]][i-1];
		mx[u][i]=max(mx[u][i-1],mx[fa[u][i-1]][i-1]);
	}
	for(int i=head[u];i;i=nxt[i])
	{
		dep[to[i]]=dep[u]+1;
		fa[to[i]][0]=u;
		mx[to[i]][0]=val[u];
		dfs(to[i]);
	}
	if(u>n) pos[++pos[0]]=u;
}
void update(int &x,int y,int l,int r,int k)
{
	x=++idx;
	sumv[x]=sumv[y]+1;
	lc[x]=lc[y];
	rc[x]=rc[y];
	if(l==r) return;
	int mid=(l+r)/2;
	if(k<=mid) update(lc[x],lc[y],l,mid,k);
	else update(rc[x],rc[y],mid+1,r,k);
}
int query(int x,int y,int l,int r,int k)
{
	if(l==r) return l;
	int mid=(l+r)/2,sum=sumv[lc[y]]-sumv[lc[x]];
	if(k<=sum) return query(lc[x],lc[y],l,mid,k);
	else return query(rc[x],rc[y],mid+1,r,k-sum);
}
void build()
{
	tot=n;
	sort(a+1,a+m+1,cmp);
	for(int i=1;i<=m;i++)
	{
		int p=findrt(a[i].u),q=findrt(a[i].v);
		if(p^q)
		{
			tot++;
			pa[p]=pa[q]=tot;
			val[tot]=a[i].d;
			adde(tot,p);
			adde(tot,q);
			if(tot==n*2-1) break;
		}
	}
	for(int i=1;i<=n;i++)
		if(!vis[i]) dfs(findrt(i));
	for(int i=1;i<=pos[0];i++)
	{
		int tmp=pos[i];
		if(tmp<=n) update(root[i],root[i-1],1,n,h[tmp]);
		else
		{
			root[i]=root[i-1];
			if(!bg[tmp]) bg[tmp]=i;
			else ed[tmp]=i;
		}
	}
}
int find(int x,int v)
{
	for(int i=17;i>=0;i--)
		if(dep[x]>=(1<<i)&&mx[x][i]<=v)
			x=fa[x][i];
	return x;
}
void solve()
{
	int ans=0,v,x,k;
	for(int i=1;i<=q;i++)
	{
		v=rd(),x=rd(),k=rd();
		if(ans!=-1) v^=ans,x^=ans,k^=ans;
		int t=find(v,x);
		int a=root[bg[t]],b=root[ed[t]];
		if(sumv[b]-sumv[a]<k) ans=-1;
		else ans=V[query(a,b,1,n,sumv[b]-sumv[a]-k+1)-1];
		printf("%d\n",ans);
	}
}
int main()
{
	n=rd(),m=rd(),q=rd();
	for(int i=1;i<=n;i++)
		V.push_back(h[i]=rd());
	sort(V.begin(),V.end());
	for(int i=1;i<=n;i++)
		h[i]=lower_bound(V.begin(),V.end(),h[i])-V.begin()+1;
	for(int i=1;i<=2*n;i++) pa[i]=i;
	for(int i=1;i<=m;i++)
		a[i].u=rd(),a[i].v=rd(),a[i].d=rd();
	build();
	solve();
	return 0;
}

终于写完了,好嗨森!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值