题意:给出一个有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. thrift 一个有意思的特性:Class名称无关性

    最近开发的一个项目,后端采用thrift框架来提供rpc服务(java语言实现),然后前端采用php语言来生成thrift client调用后台RPC服务.由于某些原因,上周我把thrift定义文件中 ...

  2. [CareerCup] 9.8 Represent N Cents 美分的组成

    9.8 Given an infinite number of quarters (25 cents), dimes (10 cents), nickels (5 cents) and pennies ...

  3. CommandBehavior.CloseConnection

    cmd.commandTimeout设置为了1秒,sql执行了很长时间还没有超时, cmd.ExecuteReader(CommandBehavior.CloseConnection)这样就会立马重现 ...

  4. php 读取csv 乱码

    在php手册里面有这样一个例子,为什么读出的是乱码<?php$row = 1;$handle = fopen("test.csv","r");while ...

  5. Publishing failed with multiple errors 异常

    Publishing failed with multiple errors 在使用eclipse发布项目时不能自动生成class文件,且无法启动调试的Tomcat服务.启动过程提示 以上 异常 解决 ...

  6. mysql中bit_count和bit_or函数的含义

    翻阅mysql手册时,看到有个示例使用了bit_or方法来去除重复的数据,一开始没看明白,后来看明白之后感觉非常巧妙.示例要实现的功能就是计算每月有几天有访问,先把示例摘录在这里. 1 2 3 4 5 ...

  7. Linux下查看软件的安装路径

    一.which 命令 Shell 的which 命令可以找出相关命令是否已经在搜索路径中. $ which git/usr/bin/git 二.whereis 命令 whereis 命令搜索更大范围的 ...

  8. mysql5.7导入csv文件

    环境: Windows10企业版X64 mysql5.7免安装版(从5.6版本开始,官方不再提供64位的msi版本) 运行mysqld.exe启动mysql进程. 用root登录mysql: mysq ...

  9. DataTable的过滤需要的数据

    DataView dv = datatable.DefaultView;           (1)      dv.RowFilter = "RowsId>3";  //此 ...

  10. 通过ipv6访问 g o o g l e

    Google.Youtube.Facebook等均支持IPv6访问,IPv4网络的用户大部分都无法访问,比如Gmail,Google Docs等等各种相关服务.而该类网站大部分均已接入IPv6网络,因 ...