1906: 树上的蚂蚁

19 篇文章 0 订阅
11 篇文章 0 订阅

1906: 树上的蚂蚁

Time Limit: 25 Sec   Memory Limit: 162 MB
Submit: 80   Solved: 15
[ Submit][ Status][ Discuss]

Description

Input

Output

Sample Input

1
3
1 2 1
2 3 1
3
1 3 2
3 1 1
1 2 3

Sample Output

2

HINT

N< = 100000

Source

[ Submit][ Status][ Discuss]

本来想复习路径求交的。。结果就这么WA飞了= =
怎么求交的话。。在3700的题解有,,,就不再说了
网上的题解都不说怎么判断相遇啊。。。。。自己写的时候情况没考虑清楚。。。。。
如果路径交是一个点,判断到达时间是否相等即可
如果是一条路径,分两类讨论
1.两只蚂蚁在路径上同向走
如果同时到达起点,或是后抵达的蚂蚁比先抵达的蚂蚁先离开,都会相遇
2.反向走
分别枚举一只蚂蚁到达起点的时间,看这个时间是否在另一只蚂蚁爬的总路程的时间段内,如果在,肯定相遇。。因为另一只蚂蚁会跑过来= =
欧拉序优化LCA就不说了= =
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 2E5 + 20;
const int N = 18;
typedef long long LL;

struct E{
	int to,w; E(){}
	E(int to,int w): to(to),w(w){}
};

int n,m,dfs_clock,T,ans,L[maxn][N],Ans[maxn][N],bin[maxn],len[maxn]
	,s[maxn],t[maxn],v[maxn],lca[maxn],dfn[maxn],A[5],dis[maxn];
bool ok[1010][1010];

vector <E> G[maxn];

bool cmp(const int &x,const int &y) {return dfn[x] < dfn[y];}

int getint()
{
	char ch = getchar(); int ret = 0;
	while (ch < '0' || '9' < ch) ch = getchar();
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret;
}

void Clear()
{
	for (int i = 1; i <= n; i++)
	{
		G[i].clear(); dis[i] = 0; dfs_clock = 0;
		//memset(Ans[i],0,sizeof(Ans[i]));
		//memset(L[i],0,sizeof(L[i]));
	}
}

void Dfs(int x,int fa)
{
	dfn[x] = ++dfs_clock;
	Ans[dfs_clock][0] = x;
	for (int i = 0; i < G[x].size(); i++)
	{
		E e = G[x][i];
		if (e.to == fa) continue;
		dis[e.to] = dis[x] + e.w;
		L[dfs_clock+1][0] = L[dfn[x]][0] + 1;
		Dfs(e.to,x); ++dfs_clock;
		L[dfs_clock][0] = L[dfn[x]][0];
		Ans[dfs_clock][0] = x;
	}
}

int LCA(int x,int y)
{
	x = dfn[x]; y = dfn[y]; if (x > y) swap(x,y);
	int le = y - x + 1,k = bin[le];
	if (L[x][k] < L[y-len[le]+1][k]) return Ans[x][k];
	else return Ans[y-len[le]+1][k];
}

int Dis(const int &x,const int &y)
{
	int lca = LCA(x,y);
	return dis[x] + dis[y] - 2*dis[lca];
}

void Pre_Work()
{
	for (int j = 1; j < N; j++)
		for (int i = 1; i <= dfs_clock; i++)
		{
			int Nex = i + (1<<j-1);
			if (Nex > dfs_clock) break;
			if (L[Nex][j-1] < L[i][j-1]) 
				L[i][j] = L[Nex][j-1],Ans[i][j] = Ans[Nex][j-1];
			else L[i][j] = L[i][j-1],Ans[i][j] = Ans[i][j-1];
		}
	m = getint();
	for (int i = 1; i <= m; i++)
	{
		s[i] = getint(); t[i] = getint();
		lca[i] = LCA(s[i],t[i]); v[i] = getint();
	}
}

void Work(const int &X,const int &Y,const int &i,const int &j)
{
	bool f1 = (Dis(A[X],s[i]) < Dis(A[Y],s[i])); int s1 = f1?A[X]:A[Y];
	bool f2 = (Dis(A[X],s[j]) < Dis(A[Y],s[j])); int s2 = f2?A[X]:A[Y];
	if (f1 == f2)
	{
		int t1 = s1 == A[X]?A[Y]:A[X],t2 = t1;
		int sa = Dis(s1,s[i]),sb = Dis(s2,s[j]);
		int sc = Dis(t1,s[i]),sd = Dis(t2,s[j]);
		if (1LL*sa*v[j] == 1LL*sb*v[i]) ++ans;
		else if (1LL*sa*v[j] <= 1LL*sb*v[i])
		{
			if (1LL*sd*v[i] <= 1LL*sc*v[j]) ++ans;
		}
		else
		{
			if (1LL*sc*v[j] <= 1LL*sd*v[i]) ++ans;
		}
	}
	else
	{
		int t1 = s1 == A[X]?A[Y]:A[X],t2 = s2 == A[X]?A[Y]:A[X];
		int sa = Dis(s1,s[i]),sb = Dis(s2,s[j]);
		int sc = Dis(t1,s[i]),sd = Dis(t2,s[j]);
		if (1LL*sa*v[j] <= 1LL*sb*v[i] && 1LL*sb*v[i] <= 1LL*sc*v[j]) ++ans;
		else if (1LL*sb*v[i] <= 1LL*sa*v[j] && 1LL*sa*v[j] <= 1LL*sd*v[i]) ++ans;
	}
}

bool Judge(int x,int i)
{
	if (LCA(x,lca[i]) != lca[i]) return 0;
	if (LCA(x,s[i]) != x && LCA(x,t[i]) != x) return 0;
	return 1;
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	for (int i = 1; i < maxn; i++)
	{
		bin[i] = (1<<bin[i-1]+1) < i?bin[i-1]+1:bin[i-1];
		len[i] = (1<<bin[i]);
	}
	T = getint();
	while (T--)
	{
		n = getint(); Clear();
		for (int i = 1; i < n; i++)
		{
			int x = getint(),y,w;
			y = getint(); w = getint();
			G[x].push_back(E(y,w));
			G[y].push_back(E(x,w));
		}
		L[1][0] = 1; Dfs(1,0); Pre_Work(); ans = 0;
		for (int i = 1; i < m; i++)
			for (int j = i + 1; j <= m; j++)
			{
				if (s[i] == s[j]) {++ans; ok[i][j] = 1; continue;}
				int Z = ans;
				A[1] = LCA(s[i],s[j]); A[2] = LCA(s[i],t[j]);
				A[3] = LCA(t[i],s[j]); A[4] = LCA(t[i],t[j]);
				sort(A + 1,A + 5,cmp); int tot = 0;
				for (int k = 1; k <= 4; k++)
					if (A[k] != A[k-1] && Judge(A[k],i) && Judge(A[k],j))
						A[++tot] = A[k];
				if (!tot) continue;
				else if (tot == 1)
				{
					int sa = Dis(A[1],s[i]),sb = Dis(A[1],s[j]);
					if (1LL*sa*v[j] == 1LL*sb*v[i]) ++ans;
				}
				else if (tot == 2) Work(1,2,i,j); else Work(2,3,i,j);
				if (Z != ans) ok[i][j] = 1;
			}
		printf("%d\n",ans);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值