BZOJ 4012 HNOI 2015 开店 动态点分治
2016-04-03 00:10
459 查看
多次询问给定点到点权在[l,r]间的所有点距离之和。
询问某个点x到其他点的距离之和,可以考虑其到根的路径上的点,发现其和可以表示为(为了简单表示,令c[x]表示x所在子树内的所有点)
c[x]到x的距离和+
{c[fa[x]]-c[x]}到fa[x]的距离和+|{c[fa[x]]-c[x]}|*dis(x,fa[x])+
….
c[fa[x]]-c[x]表示x的父亲的子树的所有点除了x子树内的所有点。
由于我们始终关心的是:一个点的子树;而不关心点间路径;意味着我们可以重构树结构。
点分治满足计算上面数据的要求,按重心构造新树再上面做文章即可。
为每个点维护其在新树上子树中各点到其距离,以及从父亲经过该点到子树中各点的距离。
而点权范围前缀和二分即可。
人生哲学。最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱。这样的
想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面
向什么样的人群。很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n
个地方,编号为 1 到 n,被 n-1 条带权的边连接起来。每个地方都住着一个妖怪,
其中第 i 个地方的妖怪年龄是 x_i。妖怪都是些比较喜欢安静的家伙,所以它们并
不希望和很多妖怪相邻。所以这个树所有顶点的度数都小于或等于 3。妖怪和人一
样,兴趣点随着年龄的变化自然就会变化,比如我们的 18 岁少女幽香和八云紫就
比较喜欢可爱的东西。幽香通过研究发现,基本上妖怪的兴趣只跟年龄有关,所以
幽香打算选择一个地方 u(u为编号),然后在 u开一家面向年龄在 L到R 之间(即
年龄大于等于 L、小于等于 R)的妖怪的店。也有可能 u这个地方离这些妖怪比较
远,于是幽香就想要知道所有年龄在 L 到 R 之间的妖怪,到点 u 的距离的和是多
少(妖怪到 u 的距离是该妖怪所在地方到 u 的路径上的边的权之和) ,幽香把这个
称为这个开店方案的方便值。幽香她们还没有决定要把店开在哪里,八云紫倒是准
备了很多方案,于是幽香想要知道,对于每个方案,方便值是多少呢。
怪的年龄上限。
第二行n个用空格分开的数 x_1、x_2、…、x_n,x_i 表示第i 个地点妖怪的年
龄,满足0<=x_i
询问某个点x到其他点的距离之和,可以考虑其到根的路径上的点,发现其和可以表示为(为了简单表示,令c[x]表示x所在子树内的所有点)
c[x]到x的距离和+
{c[fa[x]]-c[x]}到fa[x]的距离和+|{c[fa[x]]-c[x]}|*dis(x,fa[x])+
….
c[fa[x]]-c[x]表示x的父亲的子树的所有点除了x子树内的所有点。
由于我们始终关心的是:一个点的子树;而不关心点间路径;意味着我们可以重构树结构。
点分治满足计算上面数据的要求,按重心构造新树再上面做文章即可。
为每个点维护其在新树上子树中各点到其距离,以及从父亲经过该点到子树中各点的距离。
而点权范围前缀和二分即可。
#include <vector> #include <cstdio> #include <algorithm> #define FOR(i,j,k) for(i=j;i<=k;++i) const int N = 150005, M = N * 2, inf = 2147483647, K = 19; typedef long long ll; using namespace std; struct Data { ll a, b; Data() {} Data(ll c, ll d) : a(c), b(d) {} }; typedef vector<Data> Collection; bool operator< (const Data &a, const Data &b) { return a.a == b.a ? a.b < b.b : a.a < b.a; } Data operator- (const Data &a, const Data &b) { return Data(a.a - b.a, a.b - b.b); } int a ; Collection s1 , s2 ; int vis[M], p[M], v[M], h , w[M], cnt = 1, node, rt; int lb[M], dep , dis , g , sz , fa[M], lf[M][20]; void add(int a, int b, int c) { p[++cnt] = h[a]; v[cnt] = b; w[cnt] = c; h[a] = cnt; } void root(int x, int fa) { sz[x] = 1; g[x] = 0; for (int i = h[x]; i; i = p[i]) if (v[i] != fa && !vis[i]) { root(v[i], x); sz[x] += sz[v[i]]; g[x] = max(g[x], sz[v[i]]); } g[x] = max(g[x], node - sz[x]); if (g[x] < g[rt]) rt = x; } int get_root(int x, int fa, int sz) { rt = 0; node = sz; g[0] = inf; root(x, fa); return rt; } void dfs_seq(int x, int fa, int dep, Collection &s) { s.push_back(Data(a[x], dep)); for (int i = h[x]; i; i = p[i]) if (!vis[i] && v[i] != fa) dfs_seq(v[i], x, dep + w[i], s); } void work(int x) { dfs_seq(x, 0, 0, s1[x]); for (int i = h[x]; i; i = p[i]) if (!vis[i]) { vis[i] = vis[i ^ 1] = true; int cg = get_root(v[i], x, sz[v[i]]); dfs_seq(v[i], 0, w[i], s2[cg]); fa[cg] = x; work(cg); } } void process(Collection &c) { c.push_back(Data(-1, 0)); sort(c.begin(), c.end()); for (int i = 1; i < c.size(); ++i) c[i].b += c[i - 1].b; } void dfs(int x, int fa) { int i; dep[x] = dep[lf[x][0] = fa] + 1; FOR(i,1,K) lf[x][i] = lf[lf[x][i - 1]][i - 1]; for (i = h[x]; i; i = p[i]) if (v[i] != fa) { dis[v[i]] = dis[x] + w[i]; dfs(v[i], x); } } int lca(int x, int y) { if (dep[x] < dep[y]) swap(x, y); int t = dep[x] - dep[y], i; FOR(i,0,K) if ((1 << i) & t) x = lf[x][i]; for(i=K;i>=0;--i) if (lf[x][i] != lf[y][i]) x = lf[x][i], y = lf[y][i]; return x == y ? x : lf[x][0]; } int dist(int a, int b) { return dis[a] + dis[b] - 2 * dis[lca(a, b)]; } Data query(Collection &a, int l, int r) { if (a.empty()) return Data(0, 0); Collection::iterator i = lower_bound(a.begin(), a.end(), Data(l, 0)), j = lower_bound(a.begin(), a.end(), Data(r + 1, 0)); --i; --j; return Data(j->b - i->b, j - i); } int main() { int i, j, n, m; ll x, y, z, p, ans = 0; scanf("%d%d%lld", &n, &m, &p); FOR(i,1,n) scanf("%d", a + i); FOR(i,2,n) scanf("%lld%lld%lld", &x, &y, &z), add(x, y, z), add(y, x, z); work(get_root(1, 0, n)); FOR(i,1,n) process(s1[i]), process(s2[i]); dfs(1, 0); FOR(i,1,m) { scanf("%lld%lld%lld", &x, &y, &z); y = (y + last_ans) % p; z = (z + last_ans) % p; if (y > z) swap(y, z); ans = query(s1[x], y, z).a; for (int i = x; fa[i]; i = fa[i]) { Data t = query(s1[fa[i]], y, z) - query(s2[i], y, z); ans += t.a + t.b * dist(x, fa[i]); } printf("%lld\n", ans); } return 0; }
4012: [HNOI2015]开店
Description
风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学。最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱。这样的
想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面
向什么样的人群。很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n
个地方,编号为 1 到 n,被 n-1 条带权的边连接起来。每个地方都住着一个妖怪,
其中第 i 个地方的妖怪年龄是 x_i。妖怪都是些比较喜欢安静的家伙,所以它们并
不希望和很多妖怪相邻。所以这个树所有顶点的度数都小于或等于 3。妖怪和人一
样,兴趣点随着年龄的变化自然就会变化,比如我们的 18 岁少女幽香和八云紫就
比较喜欢可爱的东西。幽香通过研究发现,基本上妖怪的兴趣只跟年龄有关,所以
幽香打算选择一个地方 u(u为编号),然后在 u开一家面向年龄在 L到R 之间(即
年龄大于等于 L、小于等于 R)的妖怪的店。也有可能 u这个地方离这些妖怪比较
远,于是幽香就想要知道所有年龄在 L 到 R 之间的妖怪,到点 u 的距离的和是多
少(妖怪到 u 的距离是该妖怪所在地方到 u 的路径上的边的权之和) ,幽香把这个
称为这个开店方案的方便值。幽香她们还没有决定要把店开在哪里,八云紫倒是准
备了很多方案,于是幽香想要知道,对于每个方案,方便值是多少呢。
Input
第一行三个用空格分开的数 n、Q和A,表示树的大小、开店的方案个数和妖怪的年龄上限。
第二行n个用空格分开的数 x_1、x_2、…、x_n,x_i 表示第i 个地点妖怪的年
龄,满足0<=x_i
Output
对于每个方案,输出一行表示方便值。Sample Input
10 10 10 0 0 7 2 1 4 7 7 7 9 1 2 270 2 3 217 1 4 326 2 5 361 4 6 116 3 7 38 1 8 800 6 9 210 7 10 278 8 9 8 2 8 0 9 3 1 8 0 8 4 2 7 9 7 3 4 7 0 2 2 7 3 2 1 2 3 4
Sample Output
1603 957 7161 9466 3232 5223 1879 1669 1282 0
HINT
满足 n<=150000,Q<=200000。对于所有数据,满足 A<=10^9相关文章推荐
- CTF——图片里的英语
- 【C++ Primer plus】【第八章】函数探幽
- java之命令行参数main(String [] args)
- hdoj 2024 C语言合法标识符
- 构造方法的反射应用
- 对接收数组参数的成员方法进行反射
- ScrollView中ListView显示不全解决方法
- [Unity] Shader(着色器)之固定管线
- 为用户设置批量登录到属性!
- 成员变量反射的综合案例
- 成员方法的反射
- 可变参数的应用
- 成员变量的反射
- Java后台线程
- 在TCP网络连接上传递对象
- 静态导入
- 结题报告poj 1390
- Angularjs学习笔记1_基本技巧
- 实例化String 对象/"=="与“equals方法”/String类的不可变性
- C# 服务器、客户端学习(三)