题意:给出一个有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. Andrew N.G的机器学习公开课学习笔记(一):机器学习的动机与应用

    机器学习由对于人工智能的研究而来,是一个综合性和应用性学科,可以用来解决计算机视觉/生物学/机器人和日常语言等各个领域的问题,机器学习的目的是让计算机具有像人类的学习能力,这样做是因为我们发现,计算机 ...

  2. webapi相关知识

    1.从uri中获取参数 :后端:[FromUri] 2.从uri中获取数组参数:后端:[FromUri]string[] type  前端:type[]=1&type[]=2&type ...

  3. C#软件设计——小话设计模式原则之:依赖倒置原则DIP

    前言:很久之前就想动笔总结下关于软件设计的一些原则,或者说是设计模式的一些原则,奈何被各种bootstrap组件所吸引,一直抽不开身.群里面有朋友问博主是否改行做前端了,呵呵,其实博主是想做“全战”, ...

  4. Windows phone应用开发[21]-图片性能优化

    在windows phone 中常在列表中会常包含比较丰富文字和图片混排数据信息. 针对列表数据中除了谈到listbox等控件自身数据虚拟化问题外.虽然wp硬件设备随着SDK 8.0 发布得到应用可使 ...

  5. 移动UI设计

    移动应用UI设计模式 第二版 导航:跳板式,菜单式,选项卡式(微信)等 表单:登录表单,多步骤表单(递进式),计算表单,搜索表单,长表单等 表格:无表头表格,概览+数据型表格等 搜索:隐式搜索(滴滴打 ...

  6. linux基础知识与技能2

    3.编辑器vi的使用(vi和vim的联系)什么是编辑器?编辑器就是一款软件,它的主要作用就是用来编辑.譬如编写文件,编写代码.Windows中的常用编辑器,如自带的notepad.比较好用的notep ...

  7. Java--笔记(7)

    61.几种常见排序法的比较 排序法 平均时间 最差情形 稳定度 额外空间 冒泡 O(n2)     O(n2) 稳定 O(1) 交换     O(n2)     O(n2) 不稳定 O(1) 选择 O ...

  8. 【POJ 1390】Blocks

    http://poj.org/problem?id=1390 黑书上的例题,感觉我这辈子是想不到这样的dp了QAQ \(f(i,j,k)\)表示将\(i\)到\(j\)合并,并且假设未来会有\(k\) ...

  9. Ubuntu(基于Ubuntu)中常用的apt和dpkt命令

    apt-get sudo apt-get install package 安装包   sudo apt-get -f install 修复安装”-f = ——fix-missing”   sudo a ...

  10. Win7上安装Linux双系统

    今天帮同学在Win7上安装Linux,感觉一篇教程很不错,mark一下 原地址:Win7下U盘安装Ubuntu14.04双系统步骤详解 一.前期准备 1.大于2G的U盘一个(我的系统盘制作完成后大约占 ...