其他分享
首页 > 其他分享> > CF593D Happy Tree Party

CF593D Happy Tree Party

作者:互联网

前言

由于之前没有写过这类博客,特地补一篇

题目

洛谷

CF

讲解

如果你做过这道题: 上帝造题的七分钟2 / 花神游历各国(洛谷)

那么可能对你做这道题有帮助

我们发现,对于询问,如果除数不等于\(1\),那么在log级别的次数内,\(y_i\)即可被除为\(0\)

有了这个发现,我们就很容易求得答案

对于一次询问,暴力找出这条路径上所有不等于1的边,一旦统计数超过\(60(log_2(1e18)\approx 60)\)

这时候就会有人问了:“如果暴力爬树的时候全都是1的边不就TLE了吗?”

诶,我们用一个并查集就可以保证时间复杂度了,如果边为1,我们直接把它在并查集中连到祖先去

这样在下次就不会经过它了,从而保证时间复杂度

代码

int head[MAXN],tot;
struct edge
{
	int v,ID,nxt;
	LL w;
}e[MAXN << 1];
void Add_Edge(int x,int y,LL z,int ID)
{
	e[++tot].v = y;
	e[tot].w = z;
	e[tot].ID = ID;
	e[tot].nxt = head[x];
	head[x] = tot;
}
void Add_Double_Edge(int x,int y,LL z,int ID)
{
	Add_Edge(x,y,z,ID);
	Add_Edge(y,x,z,ID);
}

int f[MAXN][18],d[MAXN],eID[MAXN],fa[MAXN],bcj[MAXN];
LL w[MAXN];
int findSet(int x)
{
	if(bcj[x] != x) bcj[x] = findSet(bcj[x]);
	return bcj[x];
}
void dfs(int x,int FA)
{
	d[x] = d[FA] + 1;
	f[x][0] = FA;
	for(int i = 1;i <= 17;++ i) f[x][i] = f[f[x][i-1]][i-1];
	for(int i = head[x]; i ;i = e[i].nxt)
		if(!d[e[i].v])
			eID[e[i].ID] = e[i].v,w[e[i].v] = e[i].w,dfs(e[i].v,x);
}

int lca(int x,int y)
{
	if(d[x] < d[y]) swap(x,y);
	for(int i = 17;i >= 0;-- i) if(d[f[x][i]] >= d[y]) x = f[x][i];
	if(x == y) return x;
	for(int i = 17;i >= 0;-- i)
		if(f[x][i] != f[y][i])
			x = f[x][i],y = f[y][i];
	return f[x][0];
}
LL a[65],b[65];
void Get(int x,int LCA,LL *z,int &cnt)
{
	while(d[findSet(x)] > d[LCA] && cnt < 60)
	{
		x = findSet(x);
		if(w[x] == 1) bcj[x] = findSet(f[x][0]);
		else z[++cnt] = w[x];
		x = f[x][0];
	}
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read(); m = Read();
	for(int i = 1;i < n;++ i) 
	{
		int u = Read(),v = Read();
		Add_Double_Edge(u,v,Read(),i);
	}
	for(int i = 1;i <= n;++ i) bcj[i] = i;
	dfs(1,0);
	while(m--)
	{
		int opt = Read();
		if(opt == 1)
		{
			int u = Read(),v = Read(),cnta = 0,cntb = 0;
			LL val = Read();
			int LCA = lca(u,v);
			Get(u,LCA,a,cnta);
			Get(v,LCA,b,cntb);
			if(cnta + cntb >= 60) Put(0,'\n');
			else 
			{
				for(int i = 1;i <= cnta && val;++ i) val /= a[i];
				for(int i = cntb;i >= 1 && val;-- i) val /= b[i];
				Put(val,'\n');
			}
		}
		else
		{
			int p = Read();
			w[eID[p]] = Read();
		}
	}
	return 0;
}

标签:CF593D,return,int,--,Tree,60,Read,findSet,Party
来源: https://www.cnblogs.com/PPLPPL/p/13529625.html