[HDOJ 4916] Count on the path [树+乱搞]

本文介绍了一种处理大规模树状结构数据的在线查询算法,该算法能够在O(1)的时间复杂度内解决特定类型的查询问题。对于含有10^6个节点的树形结构,算法通过预处理实现高效查询,解决了不在这两个点路径上的最小节点编号的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给定一棵树,10^6个点,有10^6次询问,每次询问给出两个点,问不在这两个点之间的路上的最小的点的编号..

强制在线计算。不可以离线。

乱搞...不过比较复杂...

首先把1号点提成根,然后记录每个点属于1号点的哪个孩子。这样我们就可以判断一条路过不过根节点(即1号节点)。

若不过根节点,则答案显然为1。

若过根节点,则答案为不再这两个到根的链上的最小值,分为3部分,第一个节点所属的根节点的孩子的那个子树,第二个节点所属的根节点的孩子的那个子树,其他子树。

提前预处理出每颗子树的最小值,每颗子树上除去某条链后的最小值,所有子树中的最小次小再次小值,即可做到O(1)的回答。

因为点太多了..所以本机跑都爆栈...应该写非递归的...不过杭电有扩栈的那句话,于是愉快的水过了~

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <algorithm>

using namespace std;

inline int in() {
	char c=getchar();
	while (c<'0'||c>'9') c=getchar();
	int ans=0;
	while (c>='0'&&c<='9') {
		ans=ans*10+c-'0';
		c=getchar();
	}
	return ans;
}

struct Node {
	int f,fe,belong,min1,min2,ans,otm;
	bool visited;
};
struct Edge {
	int t,ne;
};

Node a[1000001];
Edge b[2000000];
int n,q,bp,min1,min2,min3,x,y;

void print() {
	printf("%d %d %d\n",min1,min2,min3);
	for (int i=1;i<=n;i++) {
		printf("Node:%d belong:%d min1:%d min2:%d ans:%d otm:%d\n",i,a[i].belong,a[i].min1,a[i].min2,a[i].ans,a[i].otm);
	}
}
void putedge(int x,int y) {
	b[bp].t=y;
	b[bp].ne=a[x].fe;
	a[x].fe=bp++;
}
void update(int &min1,int &min2,int &min3,int x) {
	if (x<=min1)  {
		min3=min2;
		min2=min1;
		min1=x;
	} else if (x<=min2) {
		min3=min2;
		min2=x;
	} else if (x<=min3) {
		min3=x;
	}
}
void dfs1(int i) {
	a[i].visited=true;
	a[i].belong=x;
	int min1=n+1,min2=n+1,min3=n+1;
	for (int j=a[i].fe;j!=-1;j=b[j].ne) {
		if (!a[b[j].t].visited) {
			a[b[j].t].f=i;
			dfs1(b[j].t);
			update(min1,min2,min3,min(b[j].t,a[b[j].t].min1));
		}
	}
	a[i].min1=min1;
	a[i].min2=min2;
	a[i].visited=false;
}
void dfs2(int i) {
	a[i].visited=true;
	for (int j=a[i].fe;j!=-1;j=b[j].ne) {
		if (!a[b[j].t].visited) {
			dfs2(b[j].t);
			if (min(b[j].t,a[b[j].t].min1)!=a[i].min1) a[b[j].t].otm=a[i].min1;
			else a[b[j].t].otm=a[i].min2;
		}
	}
	a[i].visited=false;
}
void dfs3(int i,int min1) {
	a[i].visited=true;
	a[i].ans=min(min1,a[i].min1);
	for (int j=a[i].fe;j!=-1;j=b[j].ne) {
		if (!a[b[j].t].visited) {
			dfs3(b[j].t,min(min1,a[b[j].t].otm));
		}
	}
	a[i].visited=false;
}
int getAns(int x,int y) {
	if (x==1||y==1) {
		x*=y;
		if (min1==min(a[x].belong,a[a[x].belong].min1)) return min(a[x].ans,min2);
		else return min1;
	} else if (a[x].belong!=a[y].belong) {
		int tmp1=min(a[x].belong,a[a[x].belong].min1);
		int tmp2=min(a[y].belong,a[a[y].belong].min1);
		int ans;
		if (min1!=tmp1&&min1!=tmp2) ans=min1;
		else if (min2!=tmp1&&min2!=tmp2) ans=min2;
		else ans=min3;
		ans=min(ans,a[x].ans);
		ans=min(ans,a[y].ans);
		return ans;
	} else return 1;
}
int main() {
	int i,ans,j;
	while (scanf("%d%d",&n,&q)!=EOF) {
		for (i=1;i<=n;i++) {
			a[i].fe=-1;
			a[i].visited=false;
		}
		bp=0;
		for (i=1;i<n;i++) {
			x=in();y=in();
			putedge(x,y);
			putedge(y,x);
		}
		min1=min2=min3=n+1;
		a[1].visited=true;
		for (j=a[1].fe;j!=-1;j=b[j].ne) {
			x=b[j].t;
			dfs1(b[j].t);
			dfs2(b[j].t);
			dfs3(b[j].t,n+1);
			//printf("update %d %d %d %d\n",min1,min2,min3,min(x,a[x].min1));
			update(min1,min2,min3,min(x,a[x].min1));
		}
		//print();
		ans=0;
		for (i=0;i<q;i++) {
			x=in();y=in();
			x^=ans;y^=ans;
			ans=getAns(x,y);
			printf("%d\n",ans);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值