您的位置:首页 > 其它

【BestCoder19 D】hdu5111:Alexandra and Two Trees

2014-11-26 15:34 351 查看

【算法】

 树链剖分,主席树。

大部分按照官方题解:

先考虑在序列上而非树上的情况。设两个序列是a和b。
我们容易找到一个函数f,使得对于任意的i满足f(a[i])=i,并且f(其他)=0。然后把每个b[i]变成f(b[i])。这样就把a变成了1,2,...,n,而原问题的答案不变。
现在问题变成了:每次问b[u2..v2]中,值是u1..v1的元素的个数。这是数据结构的经典题目,可以用线段树或树状数组(离线)或可持久化线段树(在线)做。
对于树上的问题,设两个树是A和B。
我们不可能变换树A使得每次询问在A中都是一段连续区间,但是如果对A进行轻重链剖分,使得每个链的f值是连续的,就能保证每次询问至多查询O(log n)个区间。接下来就可以套用之前的方法用线段树或树状数组(离线)或可持久化线段树(在线)做了。

具体见代码实现。

【注意】

 dfs会爆栈,需要扩大栈空间

#pragma comment(linker, "/STACK:16777216")

【参考资料】

 1、BestCoder官方题解

【代码】

代码不算长,至少是已提交的几个里最短的。但是时间貌似有点长,估计大部分用在了memset上了。
#pragma comment(linker, "/STACK:16777216")
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <math.h>
#include <string.h>
#define MEM(a) memset(a,0,sizeof(a))
#define mid ((l+r)>>1)
#define lch lc[c]
#define rch rc[c]
#define F(i,x) for (i=head[x];i;i=e[i].next)
const int MAXN = 100010;
const int MAXNODE = 2000010;
using namespace std;

int n1, n2, num[3][MAXN], ll, rr;
int lc[MAXNODE], rc[MAXNODE], s[MAXNODE], root[MAXN], numn;
int i1[MAXN][2], i2[MAXN][2], cnt1, cnt2;

struct chaindevide
{
int f[MAXN], son[MAXN], s[MAXN], dep[MAXN], top[MAXN], h[MAXN], g[MAXN], v[MAXN], T, n;
struct edge{ int u, next; }e[100010];
int nume, head[MAXN];
inline void add(int x, int u){ e[++nume].u = u, e[nume].next = head[x], head[x] = nume; }

void init(){ dep[1] = 1; }

void dfs1(int c)
{
int i, t = 0;
s[c] = 1;
F(i, c)
{
if (f[c] == e[i].u) continue;//useless
f[e[i].u] = c, dep[e[i].u] = dep[c] + 1;
dfs1(e[i].u);
s[c] += s[e[i].u];
if (s[e[i].u] > t) t = s[e[i].u], son[c] = e[i].u;
}
}

void dfs2(int c, int tp)
{
int i;
g[c] = ++T; h[T] = c;
top[c] = tp;
if (!son[c]) return;
dfs2(son[c], tp);
F(i, c) if (e[i].u != f[c] && e[i].u != son[c]) dfs2(e[i].u, e[i].u);
}

void read(int _n)
{
int i;
n = _n;
for (i = 2; i <= n; ++i) scanf("%d", &f[i]), add(f[i], i);
for (i = 1; i <= n; ++i) scanf("%d", &v[i]);
dfs1(1); dfs2(1, 1);
}

void divide(int ii[][2], int &cnt, int u, int v)
{
if (u == v)
{
++cnt;
ii[cnt][0] = ii[cnt][1] = g[u];
return;
}
while (top[u] != top[v])
{
if (dep[top[u]] < dep[top[v]]) swap(u, v);
ii[++cnt][0] = g[top[u]]; ii[cnt][1] = g[u];
u = f[top[u]];
}
ii[++cnt][0] = min(g[u], g[v]); ii[cnt][1] = max(g[u], g[v]);
}
}T[3];

struct aa{
int num, pos, v;
friend bool operator <(aa a, aa b){ return a.num < b.num || (a.num == b.num&&a.pos < b.pos); }
void init(int _n, int _p, int _v){ num = _n, pos = _p, v = _v; }
}a[200020];

void insert(int &c, int l, int r, int x)
{
lc[numn + 1] = lch, rc[numn + 1] = rch, c = ++numn;
if (l == r) { s[c] = 1; return; }
if (x <= mid) insert(lch, l, mid, x);
else insert(rch, mid + 1, r, x);
s[c] = s[lch] + s[rch];
}

int query(int c, int l, int r)
{
if (ll <= l&&r <= rr) return s[c];
return ((ll <= mid) ? query(lch, l, mid) : 0) + ((rr > mid) ? query(rch, mid + 1, r) : 0);
}

void work()
{
int i, j, t = 0, q, u1, v1, u2, v2, ans = 0;
T[1].read(n1); scanf("%d", &n2); T[2].read(n2);
for (i = 1; i <= n1; ++i) a[++t].init(T[1].v[i], 0, T[1].g[i]);
for (i = 1; i <= n1; ++i) T[1].v[i] = T[1].g[i];
for (i = 1; i <= n2; ++i) a[++t].init(T[2].v[i], i, 0);
sort(a + 1, a + 1 + t);
for (i = 1; i <= t; ++i)
{
if (!a[i].pos) continue;
if (i > 1 && a[i].num == a[i - 1].num) T[2].v[a[i].pos] = a[i - 1].v;
else T[2].v[a[i].pos] = 0;
}

for (i = 1; i <= n2; ++i)
{
root[i] = root[i - 1];
if (T[2].v[T[2].h[i]]) insert(root[i], 1, n1, T[2].v[T[2].h[i]]);
}
for (scanf("%d", &q); q; --q)
{
ans = 0;
scanf("%d%d%d%d", &u1, &v1, &u2, &v2);
T[1].divide(i1, cnt1 = 0, u1, v1);
T[2].divide(i2, cnt2 = 0, u2, v2);
for (i = 1; i <= cnt1; ++i)
{
ll = i1[i][0], rr = i1[i][1];
for (j = 1; j <= cnt2; ++j)
ans += query(root[i2[j][1]], 1, n1) - query(root[i2[j][0] - 1], 1, n1);
}
printf("%d\n", ans);
}
}

int main()
{
while (~scanf("%d", &n1))
{
MEM(T);    T[1].init(); T[2].init(); MEM(lc), MEM(rc), MEM(s), MEM(root); numn = 0;
work();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息