题意:给出一个有n(n<=200000)的树形图,每条边有一个权值。有两种操作,1是将一个边的权值变小,

2是给定两点a,b和一个值y,用y(long long范围内)依次除以两点之间的路径上的所有边的权值,每次除法都是向下取整。

并输出这个值。

操作次数为m(m<=200000)。

分析:

这是一个较难的在线LCA问题。

首先,每个y最多经过63次>=2的除数的除法就会变为0。

建树并生成LCA。

每次处理第2种请求时,我们都是先求两点的LCA,再分别处理两点到其LCA的路径。

对于从低到高走路径的过程中,连续的权值为1的边,我们用一种类似于并查集的方式将他们缩成一条边。

例如:a是b的父亲,边权值为1。那么我们领link[b]=a。否则我们令link[b]=b。

这样如果出现连续的权值为1的边,我们不断追溯其link值直到与自身相等即可。记得使用并查集的路径压缩优化。

那么我们处理单个路径时最多需要处理的边数约为63×2(权值>=2的和=1的边交替出现的情况)。

所以总复杂度为O(mlogy)

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std; #define d(x)
const int MAX_NODE_NUM = (int)(2e5) + ;
const int M = ; int n, m;
vector<pair<int, long long> > edge[MAX_NODE_NUM];
bool vis[MAX_NODE_NUM];
int father[MAX_NODE_NUM][M];
int depth[MAX_NODE_NUM];
long long value[MAX_NODE_NUM];
pair<int, int> p_edge[MAX_NODE_NUM];
int link[MAX_NODE_NUM]; void bfs(int root)
{
queue<int> q;
q.push(root);
while (!q.empty())
{
int u = q.front();
q.pop();
vis[u] = true;
for (int i = ; i < (int)edge[u].size(); i++)
{
int v = edge[u][i].first;
if (vis[v])
{
continue;
}
father[v][] = u;
depth[v] = depth[u] + ;
value[v] = edge[u][i].second;
link[v] = v;
if (u != && value[v] == )
link[v] = u;
q.push(v);
}
}
} //index start from 1.
void init_LCA(int root)
{
fill_n(vis, n + , );
memset(father, , sizeof(father));
bfs(root);
bool did;
for (int i = ; i < M; i++)
{
did = false;
for (int j = ; j <= n; j++)
{
int k = father[j][i - ];
if (k <= )
{
continue;
}
father[j][i] = father[k][i - ];
did = true;
}
if (!did)
{
break;
}
}
} //O(log(n))
int LCA(int x, int y)
{
if (depth[x] > depth[y])
{
swap(x, y);
}
int diff = depth[y] - depth[x];
for (int i = ; i < M && diff; i++)
{
if (diff & )
{
y = father[y][i];
}
diff >>= ;
}
if (x == y)
{
return x;
}
int exp = ;
while (x != y)
{
if (!exp || father[x][exp] != father[y][exp])
{
x = father[x][exp];
y = father[y][exp];
exp++;
}else
{
exp--;
}
}
return x;
} long long next_ll()
{
long long a;
scanf("%lld", &a);
return a;
} void input()
{
scanf("%d%d", &n, &m);
for (int i = ; i < n - ; i++)
{
int a, b;
long long c; scanf("%d%d", &a, &b);
c = next_ll();
edge[a].push_back(make_pair(b, c));
edge[b].push_back(make_pair(a, c));
p_edge[i] = make_pair(a, b);
}
} int get_link(int a)
{
if (a == link[a])
return a;
return link[a] = get_link(link[a]);
} void make(int a, int lca, long long &w)
{
while (w > && depth[a] > depth[lca])
{
w /= value[a];
a = father[a][];
a = get_link(a);
}
} void work(int a, int b, long long w)
{
int lca = LCA(a, b);
make(a, lca, w);
make(b, lca, w);
printf("%lld\n", w);
} void work(int p, long long w)
{
p--;
int u = p_edge[p].first;
int v = p_edge[p].second;
if (depth[u] > depth[v])
{
swap(u, v);
}
value[v]= w;
if (w == )
{
link[v] = link[u];
}
} int main()
{
input();
init_LCA();
for (int i = ; i < m; i++)
{
int command;
int a, b;
long long c;
scanf("%d", &command);
if (command == )
{
scanf("%d%d", &a, &b);
c = next_ll();
work(a, b, c);
}else
{
scanf("%d", &a);
c = next_ll();
work(a, c);
}
}
return ;
}

cf593d的更多相关文章

  1. 题解:CF593D Happy Tree Party

    题解:CF593D Happy Tree Party Description Bogdan has a birthday today and mom gave him a tree consistin ...

  2. CF593D Happy Tree Party(不用树剖)

    题面 题解 我们发现,对于除法有效的xi最小为2,yi最多除log次就会变成0,所以我们可以每次找路径上下一个>=2的xi,暴力除,当发现y=0时就停止 于是我们维护每个点向上走一直走到根最近的 ...

随机推荐

  1. 如何使用Log4net创建日志及简单扩展

    第一步:在项目中添加对log4net.dll的引用,这里引用版本是1.2.10.0.第二步:程序启动时读取log4net的配置文件.如果是CS程序,在根目录的Program.cs中的Main方法中添加 ...

  2. request.getcontextPath() 详解

    request.getcontextPath() 详解 文章分类:Java编程 <%=request.getContextPath()%>是为了解决相对路径的问题,可返回站点的根路径. 但 ...

  3. sql server pivot/unpivot 行列互转

    有时候会碰到行转列的需求(也就是将列的值作为列名称),通常我都是用 CASE END + 聚合函数来实现的. 如下: declare @t table (StudentName nvarchar(20 ...

  4. CSS3系列之3D制作

    一.序 博主最近这些天,突发奇想的想研究一下CSS3的东西,从而提升一下CSS的能力,在学习的过程中发现其实CSS3是一个挺复杂的东西,深入的研究,你可能会涉及到初中的光学理论来帮助理解一些概念,同时 ...

  5. C# 对 App.config的appSettings节点数据进行加密

    .NET平台下的Winform和Asp.net的配置文件默认都是明文保存的,本文使用的是.Net自身如何加密配置文件,不包含自定义的加密规则 但.Net是提供了直接对配置文件加密的功能的,使用.Net ...

  6. jQuery之Ajax--底层接口

    1. $.ajax()方法:是jQuery最底层的Ajax实现.它的结构为:$.ajax(options).该方法只有一个参数,但在这个对象里面包含了$.ajax()方法所需要的请求设置以及回调函数等 ...

  7. JQuery对id中含有特殊字符的转义处理

    转载--http://www.jb51.net/article/41192.htm <div id="a[]">kkkkkk</div> <scrip ...

  8. ob_start()

    ob_start()函数用于打开缓冲区 1.用于header()之前 ob_start(); //打开缓冲区 echo "Hellon"; //输出 header("lo ...

  9. 教你一招:解决windows xp系统开机出现“disk checking has been canceled”

    问题重现: 问题分析: 系统的注册表被修改了. 问题解决: 1.(临时解决)开机时,按ESC或ENTER键取消. 2.(彻底解决)修改注册表文件. Win + R 打开运行 Regedit ,进入注册 ...

  10. SpringBoot源码分析:spring的基本架构

    在深入了解springboot之前,我们需要了解spring,springboot本身就是基于spring而构建:是微服务架构中一个比较流行的框架:类似spring提供了一套完整的微服务方案如spri ...