• [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,'
    ');
    			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,'
    ');
    			}
    		}
    		else
    		{
    			int p = Read();
    			w[eID[p]] = Read();
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    区间覆盖(线段树)
    差分约束
    二维数组
    P1195 口袋的天空
    dp的刷表法和填表法
    P1284 三角形牧场
    数据库课程设计
    具体解释VB中连接access数据库的几种方法
    android之PackageManager简单介绍
    Oracle fga审计有这几个特性
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/13529625.html
Copyright © 2020-2023  润新知