POJ 3417 Network 树上差分 LCA 链式前向星 仍超时,加上快读过

3417 -- Network

东改西改看各种题解,感觉没问题了呀,还是超时。直到我加上快读...

const int maxn = 100005;

inline int read()
{
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch>'9')
	{
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
	{
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x * f;
}
inline void write(int x)
{
	if (x < 0)
	{
		putchar('-');
		x = -x;
	}
	if (x > 9)
		write(x / 10);
	putchar(x % 10 + '0');
}
//
struct node
{
	int b, next;
}edges[maxn*2];
int head[maxn];
int k = 0;
inline void add(int a, int b)
{
	k++;
	edges[k].b = b;
	edges[k].next = head[a];
	head[a] = k;
}
int fa[maxn][23];
int dep[maxn];
void dfs1(int cur ,int pa)
{
	dep[cur] = dep[pa] + 1;
	fa[cur][0] = pa;
	for (int p = 1; p < 22; p++)
		fa[cur][p] = fa[fa[cur][p - 1]][p - 1];

	for (int i = head[cur]; i > 0; i = edges[i].next)
	{
		if(edges[i].b != pa)
			dfs1(edges[i].b, cur);
	}
}
inline int LCA(int a,int b)
{
	if (dep[a] < dep[b])swap(a, b);
	while (dep[a] > dep[b])
	{
		int dis = (int)log2(dep[a] - dep[b]);
		a = fa[a][dis];
	}
	if (a == b)return a;
	for (int i = log2(dep[a]); i >= 0; i--)
	{
		if (fa[a][i] != fa[b][i])
		{
			a = fa[a][i];
			b = fa[b][i];
		}
	}
	if (a != b)
	{
		a = b = fa[a][0];
	}
	return a;
}
int diff[maxn];
int pass[maxn];
int cnt0, cnt1;
void dfs2(int cur,int pa)
{
	pass[cur] += diff[cur];
	for (int i = head[cur]; i > 0; i = edges[i].next)
	{
		if (edges[i].b != pa)
		{
			dfs2(edges[i].b, cur);
			pass[cur] += pass[edges[i].b];
		}
	}
}
void solve()
{
	int n, m;
	n = read(); m = read();
	int a, b;
	for (int i = 0; i < n - 1; i++)
	{
		a = read(); b = read();
		add(a, b);
		add(b, a);
	}

	dfs1(1, 0);

	for (int i = 0; i < m; i++)
	{
		a = read(); b = read();
		diff[a]++;
		diff[b]++;
		diff[LCA(a, b)]-=2;
	}
	dfs2(1,0);
	int ans = 0;
	for (int i = 2; i <= n; i++)
	{
		if (pass[i] == 0)
			ans += m;
		else if (pass[i] == 1)
			ans++;
	}
	write(ans);
}
signed main()
{
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int t = 1;
	//cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值