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\)<A。(年龄是可以为 0的,例如刚出生的妖怪的年龄为 0。)

接下来 n-1 行,每行三个用空格分开的数 a、b、c,表示树上的顶点 a 和 b 之

间有一条权为c(1 <= c <= 1000)的边,a和b 是顶点编号。

接下来Q行,每行三个用空格分开的数 u、 a、 b。对于这 Q行的每一行,用 a、

b、A计算出 L和R,表示询问“在地方 u开店,面向妖怪的年龄区间为[L,R]的方

案的方便值是多少”。对于其中第 1 行,L 和 R 的计算方法为:L=min(a%A,b%A),

R=max(a%A,b%A)。对于第 2到第 Q行,假设前一行得到的方便值为 ans,那么当

前行的 L 和 R 计算方法为: L=min((a+ans)%A,(b+ans)%A),

R=max((a+ans)%A,(b+ans)%A)。

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


思路

很显然可以用动态点分治做

一开始想到要维护size和sumdistans就果断线段树了

然后就又MLE又RE

后来发现信息是静态的,没有修改我怎么才发现

然后就可以直接上vector大法+二分了

还不用离散化真好。。。。


线段树:

#include<bits/stdc++.h>

using namespace std;

int read() {
int res = 0, w = 1; char c = getchar();
while (!isdigit(c) && c != '-') c = getchar();
if (c == '-') w = -1, c = getchar();
while (isdigit(c)) res = (res << 1) + (res << 3) + c - '0', c = getchar();
return res * w;
} typedef long long ll;
typedef pair<ll, int> pi;
const int N = 2e5 + 10;
const int LOG = 40; struct Edge {
int v, w, nxt;
Edge(int v = 0, int w = 0, int nxt = 0): v(v), w(w), nxt(nxt) {}
} E[N << 1];
int head[N], tot = 0;
int n, q, A, num_age, age[N], pre[N];
char c[10]; void addedge(int u, int v, int w) {
E[++tot] = Edge(v, w, head[u]);
head[u] = tot;
} namespace LCA { struct Node {
int id, depth;
Node(int id = 0, int depth = 0): id(id), depth(depth) {}
bool operator < (const Node b) const {
return depth < b.depth;
}
} ST[N << 1][LOG];
int first[N], dep[N], log[N << 1], dist[N], len; void dfs(int u, int fa) {
ST[++len][0] = Node(u, dep[u]);
first[u] = len;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == fa) continue;
dep[v] = dep[u] + 1;
dist[v] = dist[u] + E[i].w;
dfs(v, u);
ST[++len][0] = Node(u, dep[u]);
}
} void init() {
dfs(1, 0);
log[1] = 0;
for (int i = 2; i <= len; i++) log[i] = log[i >> 1] + 1;
for (int j = 1; (1 << j) <= len; j++) {
for (int i = 1; i + (1 << j) - 1 <= len; i++) {
ST[i][j] = min(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
}
}
} int getdis(int u, int v) {
if (first[u] < first[v]) swap(u, v);
int k = log[first[u] - first[v] + 1];
int lca = min(ST[first[v]][k], ST[first[u] - (1 << k) + 1][k]).id;
return dist[u] + dist[v] - (dist[lca] << 1);
} } namespace Segment_Tree { int tot = 0, rt[N << 1], ls[(N * LOG) << 1], rs[(N * LOG) << 1];
ll val[(N * LOG) << 1], siz[(N * LOG) << 1]; void modify(int &t, int l, int r, int pos, int vl) {
if (!t) t =++tot;
val[t] += vl, siz[t]++;
if (l == r) return;
int mid = (l + r) >> 1;
if (pos <= mid) modify(ls[t], l, mid, pos, vl);
else modify(rs[t], mid + 1, r, pos, vl);
} pi query(int t, int l, int r, int ql, int qr) {
if (!t) return pi(0ll, 0);
if (ql <= l && r <= qr) return pi(val[t], siz[t]);
int mid = (l + r) >> 1;
if (qr <= mid) return query(ls[t], l, mid, ql, qr);
else if (ql > mid) return query(rs[t], mid + 1, r, ql, qr);
else {
pi ansl = query(ls[t], l, mid, ql, mid);
pi ansr = query(rs[t], mid + 1, r, mid + 1, qr);
return pi(ansl.first + ansr.first, ansl.second + ansr.second);
}
} } namespace Tree_Devide { int father[N], siz[N], F[N], siz_all, root;
bool vis[N]; void getsiz(int u, int fa) {
siz[u] = 1;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == fa || vis[v]) continue;
getsiz(v, u);
siz[u] += siz[v];
}
} void getroot(int u, int fa) {
F[u] = 0;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == fa || vis[v]) continue;
getroot(v, u);
F[u] = max(F[u], siz[v]);
}
F[u] = max(F[u], siz_all - siz[u]);
if (F[u] < F[root]) root = u;
} void solve(int u, int fa) {
father[u] = fa;
vis[u] = 1;
getsiz(u, 0);
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (vis[v]) continue;
F[root = 0] = siz_all = siz[v];
getroot(v, 0);
solve(root, u);
}
} void init() {
getsiz(1, 0);
F[root = 0] = siz_all = n;
getroot(1, 0);
solve(root, 0);
} #define ID0(p) (p)
#define ID1(p) (p + n) void modify_tree(int u) {
using namespace Segment_Tree;
modify(rt[ID0(u)], 1, num_age, age[u], 0);
for (int cur = u; father[cur]; cur = father[cur]) {
int dis = LCA::getdis(u, father[cur]);
modify(rt[ID0(father[cur])], 1, num_age, age[u], dis);
modify(rt[ID1(cur)], 1, num_age, age[u], dis);
}
} ll query_tree(int u, int l, int r) {
using namespace Segment_Tree;
ll res = query(rt[ID0(u)], 1, num_age, l, r).first;
pi now;
for (int cur = u; father[cur]; cur = father[cur]) {
int dis = LCA::getdis(u, father[cur]);
now = query(rt[ID0(father[cur])], 1, num_age, l, r);
res += now.first + 1ll * dis * now.second;
now = query(rt[ID1(cur)], 1, num_age, l, r);
res -= now.first + 1ll * dis * now.second;
}
return res;
} } int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
n = read(), q = read(), A = read();
for (int i = 1; i <= n; i++) {
pre[i] = age[i] = read();
}
sort(pre + 1, pre + n + 1);
num_age = unique(pre + 1, pre + n + 1) - pre - 1;
for (int i = 1; i <= n; i++) {
age[i] = lower_bound(pre + 1, pre + num_age + 1, age[i]) - pre;
}
for (int i = 1; i < n; i++) {
int u = read(), v = read(), w = read();
addedge(u, v, w);
addedge(v, u, w);
}
LCA::init();
Tree_Devide::init();
for (int i = 1; i <= n; i++) {
Tree_Devide::modify_tree(i);
}
ll lastans = 0;
while (q--) {
int u = read(), l = (read() % A + lastans % A) % A, r = (read() % A + lastans % A) % A;
if (l > r) swap(l, r);
l = lower_bound(pre + 1, pre + num_age + 1, l) - pre;
r = upper_bound(pre + 1, pre + num_age + 1, r) - pre - 1;
lastans = Tree_Devide::query_tree(u, l, r);
printf("%lld\n", lastans);
}
return 0;
}

vector+二分

#include<bits/stdc++.h>

using namespace std;

int read() {
int res = 0, w = 1; char c = getchar();
while (!isdigit(c) && c != '-') c = getchar();
if (c == '-') w = -1, c = getchar();
while (isdigit(c)) res = (res << 1) + (res << 3) + c - '0', c = getchar();
return res * w;
} typedef long long ll;
typedef pair<int, ll> pi;
const int INF_of_int = 1e9;
const int N = 2e5 + 10;
const int LOG = 40; struct Edge {
int v, w, nxt;
Edge(int v = 0, int w = 0, int nxt = 0): v(v), w(w), nxt(nxt) {}
} E[N << 1];
int head[N], tot = 0;
int n, q, A, age[N]; void addedge(int u, int v, int w) {
E[++tot] = Edge(v, w, head[u]);
head[u] = tot;
} namespace LCA { struct Node {
int id, depth;
Node(int id = 0, int depth = 0): id(id), depth(depth) {}
bool operator < (const Node b) const {
return depth < b.depth;
}
} ST[N << 1][LOG];
int first[N], dep[N], log[N << 1], dist[N], len; void dfs(int u, int fa) {
ST[++len][0] = Node(u, dep[u]);
first[u] = len;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == fa) continue;
dep[v] = dep[u] + 1;
dist[v] = dist[u] + E[i].w;
dfs(v, u);
ST[++len][0] = Node(u, dep[u]);
}
} void init() {
dfs(1, 0);
log[1] = 0;
for (int i = 2; i <= len; i++) log[i] = log[i >> 1] + 1;
for (int j = 1; (1 << j) <= len; j++) {
for (int i = 1; i + (1 << j) - 1 <= len; i++) {
ST[i][j] = min(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
}
}
} int getdis(int u, int v) {
if (first[u] < first[v]) swap(u, v);
int k = log[first[u] - first[v] + 1];
int lca = min(ST[first[v]][k], ST[first[u] - (1 << k) + 1][k]).id;
return dist[u] + dist[v] - (dist[lca] << 1);
} } namespace Tree_Devide { int father[N], siz[N], F[N], siz_all, root;
bool vis[N];
vector<pi> sum[2][N]; void getsiz(int u, int fa) {
siz[u] = 1;
sum[0][root].push_back(pi(age[u], LCA::getdis(u, root)));
sum[1][root].push_back(pi(age[u], LCA::getdis(u, father[root])));
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == fa || vis[v]) continue;
getsiz(v, u);
siz[u] += siz[v];
}
} void getroot(int u, int fa) {
F[u] = 0;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == fa || vis[v]) continue;
getroot(v, u);
F[u] = max(F[u], siz[v]);
}
F[u] = max(F[u], siz_all - siz[u]);
if (F[u] < F[root]) root = u;
} void solve(int u, int fa) {
father[u] = fa;
vis[u] = 1;
sum[0][u].push_back(pi(-INF_of_int, 0));
sum[1][u].push_back(pi(-INF_of_int, 0));
getsiz(u, 0);
sum[0][u].push_back(pi(INF_of_int + 1, 0));
sum[1][u].push_back(pi(INF_of_int + 1, 0));
sort(sum[0][u].begin(), sum[0][u].end());
sort(sum[1][u].begin(), sum[1][u].end());
int len;
len = sum[0][u].size();
for (int i = 1; i < len; i++) sum[0][u][i].second += sum[0][u][i - 1].second;
len = sum[1][u].size();
for (int i = 1; i < len; i++) sum[1][u][i].second += sum[1][u][i - 1].second;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (vis[v]) continue;
F[root = 0] = siz_all = siz[v];
getroot(v, 0);
solve(root, u);
}
} void init() {
getsiz(1, 0);
F[root = 0] = siz_all = n;
getroot(1, 0);
solve(root, 0);
} pi query(int u, int typ, int vl) {
int l = 1, r = sum[typ][u].size() - 1, res = 0;
while (l <= r) {
int mid = (l + r) >> 1;
if (sum[typ][u][mid].first <= vl) res = mid, l = mid + 1;
else r = mid - 1;
}
return pi(res, sum[typ][u][res].second);
} pi query(int u, int typ, int l, int r) {
pi ansl = query(u, typ, l - 1);
pi ansr = query(u, typ, r);
return pi(ansr.first - ansl.first, ansr.second - ansl.second);
} ll query_tree(int u, int l, int r) {
ll res = query(u, 0, l, r).second;
pi now;
for (int cur = u; father[cur]; cur = father[cur]) {
int dis = LCA::getdis(u, father[cur]);
now = query(father[cur], 0, l, r);
res += now.second + 1ll * dis * now.first;
now = query(cur, 1, l, r);
res -= now.second + 1ll * dis * now.first;
}
return res;
} } int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
n = read(), q = read(), A = read();
for (int i = 1; i <= n; i++) age[i] = read();
for (int i = 1; i < n; i++) {
int u = read(), v = read(), w = read();
addedge(u, v, w);
addedge(v, u, w);
}
LCA::init();
Tree_Devide::init();
ll lastans = 0;
while (q--) {
int u = read(), l = (read() % A + lastans % A) % A, r = (read() % A + lastans % A) % A;
if (l > r) swap(l, r);
lastans = Tree_Devide::query_tree(u, l, r);
printf("%lld\n", lastans);
}
return 0;
}

BZOJ4012: [HNOI2015]开店【动态点分治】的更多相关文章

  1. [BZOJ4012][HNOI2015]开店(动态点分治,树链剖分)

    4012: [HNOI2015]开店 Time Limit: 70 Sec  Memory Limit: 512 MBSubmit: 2168  Solved: 947[Submit][Status] ...

  2. 【bzoj4012】[HNOI2015]开店 动态点分治+STL-vector

    题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的想法当然非常好啦,但是她们也发现她们面临着一个问题 ...

  3. 【BZOJ4012】[HNOI2015]开店 动态树分治+二分

    [BZOJ4012][HNOI2015]开店 Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点 ...

  4. P3241 [HNOI2015]开店 动态点分治

    \(\color{#0066ff}{ 题目描述 }\) 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想 ...

  5. luogu 3241 [HNOI2015]开店 动态点分治+二分+vector

    独立写出来+想出来的,1.5h就切了~ 建立点分树,然后用 $vector$ 暴力存所有子节点,然后二分一下子就可以了. #include <cstdio> #include <ve ...

  6. BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector

    题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...

  7. BZOJ4012 [HNOI2015]开店 (动态点分治)

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

  8. [loj2116]「HNOI2015」开店 动态点分治

    4012: [HNOI2015]开店 Time Limit: 70 Sec  Memory Limit: 512 MBSubmit: 2452  Solved: 1089[Submit][Status ...

  9. BZOJ4012 [HNOI2015]开店

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

随机推荐

  1. Android初体验之Monkey和MonkeyRunner

    原文地址https://blog.csdn.net/mad1989/article/details/38087737 Monkey 什么是Monkey Monkey是Android中的一个命令行工具, ...

  2. 001-springmvc之原理图

    1.流程. 2.时序图. 3.方法调用. (0)DispatcherServlet类.提供了HandlerMapping成员关联关系. /** MultipartResolver used by th ...

  3. VS2010/MFC编程入门之前言

    鸡啄米的C++编程入门系列给大家讲了C++的编程入门知识,大家对C++语言在语法和设计思想上应该有了一定的了解了.但是教程中讲的例子只是一个个简单的例程,并没有可视化窗口.鸡啄米在这套VS2010/M ...

  4. 2016-2017 CT S03E07: Codeforces Trainings Season 3 Episode 7

    B. Pen Pineapple Apple Pen Solved. 题意:将一个序列合并成一个数. 思路:分类讨论一下, 水. #include<bits/stdc++.h> using ...

  5. cocos2dx 3.x 拼图小游戏

    .h #define IMAGE_MAX 2 //图片的个数.. //图片结构体 属性 struct IMAGE_DATA { cocos2d::Sprite *m_pImage; bool m_bO ...

  6. POJ2533_Longest Ordered Subsequence (线性动态规划变形)

    本题求一个字符串中的最长递增子序列的长度. 动态规划方程 a[]记录字符串: d[i]记录以第i个元素为最后一个元素的最长递增序列的长度 则 d[i+1]=1+max(d[j])  其中(j<i ...

  7. Linux配置NFS实现共享

    (1)安装相应rpm包 sudo rpm -ivh nfs-utils-1.2.3-70.el6.x86_64.rpm (2)配置共享目录:sudo vim /etc/exports /app/sof ...

  8. ZOJ 2314 Reactor Cooling(无源汇上下界网络流)

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2314 题意: 给出每条边流量的上下界,问是否存在可行流,如果存在则输出. ...

  9. BZOJ 1269 【AHOI2006】 文本编辑器

    题目链接:文本编辑器 这道题没啥好说的,直接上\(Splay\)就行了,板子题…… 但是我某个地方忘了下放标记导致调了一晚上 听说有个东西叫\(rope\)可以直接过?然而我并不会 保存一发板子: # ...

  10. CSS 再学习,基础篇

    语法 h1 {color:red; font-size:14px;} 共享声明 h1,h2,h3,h4,h5,h6 { color: green; } 继承 通过 CSS 继承,子元素将继承最高级元素 ...