您的位置:首页 > 其它

BZOJ4012 [HNOI2015]开店

2015-04-29 22:34 337 查看
首先这个叫"动态点分治",不过瞎YY也能YY出来【比如我。。。

就是记录下点分治的过程和每个点的答案信息,于是查询的时候只要沿着分治好的根一路走下去就行了,于是单次查询的外层复杂度是$O(log n)$的

对于每个点,要记录以从整棵树到它的分治路径和以它为根的子树内权值小于v的点到它的距离和(就是关于权值的前缀和)

于是查询一个点的时候只要二分一下就好了。。。

总复杂度$O((n + Q) * log^2n)$

写了一晚上QAQQQ

/**************************************************************
Problem: 4012
User: rausen
Language: C++
Result: Accepted
Time:28756 ms
Memory:107560 kb
****************************************************************/

#include <cstdio>
#include <algorithm>
#include <vector>

using namespace std;
typedef long long ll;
const int N = 15e4 + 4;

inline int read();
inline void print(ll);

struct edge {
int next, to, v;
edge(int _n = 0, int _t = 0, int _v = 0) : next(_n), to(_t), v(_v) {}
} e[N << 1];

struct data {
int v;
ll dis;
data(int _v = 0, ll _d = 0) : v(_v), dis(_d) {}

inline bool operator < (const data &p) const {
return v == p.v ? dis < p.dis : v < p.v;
}
};

struct Path {
int p, s;
ll dis;
Path(int _p = 0, ll _d = 0, int _s = 0) : p(_p), dis(_d), s(_s) {}
};

struct tree_node {
int v, sz, mx, vis;
vector <Path> path;
vector <data> dis[3];
} tr
;

int n, m, mod;
int size, root;
int first
, tot;
int L, R;
ll ans;

inline void Add_Edges(int x, int y, int z) {
e[++tot] = edge(first[x], y, z), first[x] = tot;
e[++tot] = edge(first[y], x, z), first[y] = tot;
}

#define y e[x].to
void get_sz(int p, int fa) {
int x;
tr[p].sz = 1;
for (x = first[p]; x; x = e[x].next)
if (!tr[y].vis && y != fa) {
get_sz(y, p);
tr[p].sz += tr[y].sz;
}
}

void get_rt(int p, int fa) {
int x;
tr[p].sz = 1, tr[p].mx = 0;
for (x = first[p]; x; x = e[x].next)
if (!tr[y].vis && y != fa) {
get_rt(y, p);
tr[p].sz += tr[y].sz;
tr[p].mx = max(tr[p].mx, tr[y].sz);
}
tr[p].mx = max(tr[p].mx, size - tr[p].sz);
if (tr[p].mx < tr[root].mx) root = p;
}

void calc(int p, int fa, int tar, int d, int now) {
int x;
tr[p].path.push_back(Path(tar, d, now));
tr[tar].dis[now].push_back(data(tr[p].v, d));
for (x = first[p]; x; x = e[x].next)
if (!tr[y].vis && y != fa)
calc(y, p, tar, d + e[x].v, now);
}

void work(int p) {
int x, now = 0;
tr[p].vis = 1;
get_sz(p, 0);
tr[p].path.push_back(Path(p, 0, 3));
for (x = first[p]; x; x = e[x].next)
if (!tr[y].vis) calc(y, p, p, e[x].v, now++);
for (x = first[p]; x; x = e[x].next)
if (!tr[y].vis) {
root = 0, size = tr[y].sz;
get_rt(y, 0);
work(root);
}
}
#undef y

inline ll query(vector <data> *v, ll d, int s) {
static ll res;
static int i, t;
for (i = res = 0; i < 3; ++i) if (i != s) {
t = lower_bound(v[i].begin(), v[i].end(), data(L, -1)) - v[i].begin();
if (t) res -= d * t + v[i][t - 1].dis;
t = lower_bound(v[i].begin(), v[i].end(), data(R + 1, -1)) - v[i].begin();
if (t) res += d * t + v[i][t - 1].dis;
}
return res;
}

int main() {
int i, j, k, x, y, z, Q, p;
n = read(), Q = read(), mod = read();
for (i = 1; i <= n; ++i) tr[i].v = read();
for (i = 1; i < n; ++i) {
x = read(), y = read(), z = read();
Add_Edges(x, y, z);
}
tr[root = 0].mx = size = n;
get_rt(1, 0);
work(root);
for (i = 1; i <= n; ++i)
for (j = 0; j < 3; ++j) {
sort(tr[i].dis[j].begin(), tr[i].dis[j].end());
for (k = 1; k < tr[i].dis[j].size(); ++k)
tr[i].dis[j][k].dis += tr[i].dis[j][k - 1].dis;
}
for (ans = 0; Q; --Q) {
p = read(), L = (ans + read()) % mod, R = (ans + read()) % mod;
if (L > R) swap(L, R);
for (i = ans = 0; i < tr[p].path.size(); ++i) {
if (L <= tr[tr[p].path[i].p].v && tr[tr[p].path[i].p].v <= R)
ans += tr[p].path[i].dis;
ans += query(tr[tr[p].path[i].p].dis, tr[p].path[i].dis, tr[p].path[i].s);
}
print(ans);
}
return 0;
}

inline int read() {
static int x;
static char ch;
x = 0, ch = getchar();
while (ch < '0' || '9' < ch)
ch = getchar();
while ('0' <= ch && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x;
}

inline void print(ll t) {
static int tot, pr[20];
tot = 0;
while (t)
pr[++tot] = t % 10, t /= 10;
if (!tot) putchar('0');
while (tot) putchar(pr[tot--] + '0');
putchar('\n');
}


View Code
(p.s. bz上AC700T纪念!)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: