题意:给两棵树T1,T2,点数分别为n1,n2。。保证T1中每个点权值都不同,保证T2中每个点权值都不同。。进行q次询问,每次问T1中u1到v1的路径 与 T2中u2到v2的路径 权值交集 集合 大小是多少?
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5111
解法:两种方法。。一种是主席树,可以支持这个问题的在线问题,我们先考虑对于两个数列,每次问两个数列的子列的交集大小。。这个问题。。具体问题可以看CDOJ 1104。。http://acm.uestc.edu.cn/#/problem/show/1104。。由于保证权值分别各不相同,我们记录下数列A每个位置在数列B中出现的位置p,,将数列B建立(n2+1)棵主席树,主席树上1..n1是以A的位置为下标,,每次将记录下来的位置p在主席树上更新。。对于询问查询即可。。相信熟悉的一定懂。。那么对于这个问题,查询第二棵树T2,实际上是要查询4次,即ans(u2) + ans(v2) - ans(lca(u2, v2)) - ans(fa(lca(u2, v2)))。。对于第一棵树,进行树链剖分,这样就类似于CDOJ1104那道题,每次查询一段重链。。最多log次查询。。主席树上是按照第二棵树的dfs序为下标来建的。。复杂度为loglog
还有一种方法是树状数组,但对于询问要离线处理,基本思想和主席树一样,,都用到了前缀和方法,或者说容斥
主席树+树链剖分(平均3500ms)
//Hello. I'm Peter.
#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<ctime>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
#define N 100010
int n1, n2, val1[N], val2[N], mapto[N];
vector<int>v1[N],v2[N];
struct Data{
int id, x;
}d1[N], d2[N];
bool cmp1(const Data a, const Data b){
return a.x < b.x;
}
int dep2[N], fa2[N], vto2[N], dfsclock2, maxidep2, num2[N];
void dfs2(int now, int fa){
maxidep2 = max(maxidep2, dep2[now]);
num2[now] = 1;
for(int i = 0; i < v2[now].size(); i++){
int to = v2[now][i];
fa2[to] = now;
dep2[to] = dep2[now] + 1;
dfs2(to, now);
num2[now] += num2[to];
}
}
int upto2[N];
void dfs3(int now, int fa){
vto2[now] = ++dfsclock2;
int e = -1, maxi = -1;
for(int i = 0; i < v2[now].size(); i++){
int to = v2[now][i];
if(num2[to] > maxi){
maxi = num2[to];
e = i;
}
}
if(e != -1){
upto2[v2[now][e]] = upto2[now];
dfs3(v2[now][e], now);
}
for(int i = 0; i < v2[now].size(); i++){
int to = v2[now][i];
if(i == e) continue;
upto2[to] = to;
dfs3(to, now);
}
}
int dep1[N], fa1[N], maxidep1;
void dfs1(int now, int fa){
maxidep1 = max(maxidep1, dep1[now]);
for(int i = 0; i < v1[now].size(); i++){
int to = v1[now][i];
dep1[to] = dep1[now] + 1;
fa1[to] = now;
dfs1(to, now);
}
}
#define M 18
int lc2[N][M], lc1[N][M];
void init(int *fa, int lc[][M], int maxidep, int n){
for(int i = 1; i <= n; i++) lc[i][0] = fa[i];
for(int j = 1; 1<<j <= maxidep; j++){
for(int i = 1; i <= n; i++){
if(lc[i][j-1] != 0) lc[i][j] = lc[ lc[i][j-1] ][j-1];
else lc[i][j] = 0;
}
}
}
int lca(int a,int b,int lc[][M], int *dep, int *fa){
if(a == b) return a;
if(dep[a] < dep[b]) swap(a, b);
int log = 0;
for(log = 0; 1<<log <= dep[a]; log++);
log--;
for(int i = log; i >= 0; i--){
if(lc[a][i] != 0 && dep[lc[a][i]] >= dep[b]) a = lc[a][i];
}
if(a == b) return a;
for(int i = log; i >= 0; i--){
if(lc[a][i] != 0 && lc[a][i] != lc[b][i]){
a = lc[a][i];
b = lc[b][i];
}
}
return fa[a];
}
#define MAXN N * (4 + M)
int lch[MAXN], rch[MAXN], val[MAXN], T[N], nnod;
int plant(int l,int r){
int t = ++nnod;
val[t] = 0;
if(l == r) return t;
int mid = (l + r) >> 1;
lch[t] = plant(l, mid);
rch[t] = plant(mid + 1, r);
return t;
}
int update(int id,int p,int l,int r,int v){
int t = ++nnod;
lch[t] = lch[id], rch[t] = rch[id], val[t] = val[id] + v;
if(l == r) return t;
int mid = (l + r) >> 1;
if(p <= mid) lch[t] = update(lch[t], p, l, mid, v);
else rch[t] = update(rch[t], p, mid + 1, r, v);
return t;
}
int query(int lid,int rid,int ql,int qr,int l,int r){
if(ql == l && qr == r) return val[rid] - val[lid];
int mid = (l + r) >> 1;
if(qr <= mid) return query(lch[lid], lch[rid], ql, qr, l, mid);
else if(mid < ql) return query(rch[lid], rch[rid], ql, qr, mid + 1, r);
else return query(lch[lid], lch[rid], ql, mid, l, mid) + query(rch[lid], rch[rid], mid + 1, qr, mid + 1, r);
}
int l1,r1,l2,r2,lca1,lca2;
bool pr = 1;
int query(int fr, int to){
return query(T[lca1], T[l1], fr, to, 1, n2) + query(T[fa1[lca1]], T[r1], fr, to, 1, n2);
}
int jump(int now, int to, bool ach){
int ans = 0;
while(true){
if(ach && dep2[now] < dep2[to]) break;
else if(!ach && dep2[now] <= dep2[to]) break;
if(dep2[upto2[now]] <= dep2[to]){
if(ach) ans += query(vto2[to], vto2[now]);
else ans += query(vto2[to] + 1, vto2[now]);
break;
}
ans += query(vto2[upto2[now]], vto2[now]);
now = fa2[upto2[now]];
}
return ans;
}
int main(){
while(~scanf("%d",&n1)){
for(int i = 1; i <= n1; i++) v1[i].clear();
for(int i = 2; i <= n1; i++){
int f; scanf("%d",&f);
v1[f].push_back(i);
}
for(int i = 1; i <= n1; i++){
scanf("%d",val1 + i);
d1[i].x = val1[i], d1[i].id = i;
}
scanf("%d",&n2);
for(int i = 1; i <= n2; i++) v2[i].clear();
for(int i = 2; i <= n2; i++){
int f; scanf("%d",&f);
v2[f].push_back(i);
}
for(int i = 1; i <= n2; i++){
scanf("%d",val2 + i);
d2[i].x = val2[i], d2[i].id = i;
}
dep2[0] = -1;
maxidep2 = dep2[1] = 0;
fa2[1] = 0;
dfs2(1, 0);
upto2[1] = 1;
dfsclock2 = 0;
dfs3(1, 0);
dep1[0] = -1;
maxidep1 = dep1[1] = 0;
fa1[1] = 0;
dfs1(1, 0);
init(fa1, lc1, maxidep1, n1);
init(fa2, lc2, maxidep2, n2);
sort(d1 + 1, d1 + 1 + n1, cmp1);
sort(d2 + 1, d2 + 1 + n2, cmp1);
for(int i = 1; i <= n1; i++) mapto[i] = 0;
int t1 = 1, t2 = 1;
while(t1 <= n1 && t2 <= n2){
while(t1 <= n1 && t2 <= n2 && d1[t1].x < d2[t2].x) t1++;
while(t1 <= n1 && t2 <= n2 && d1[t1].x > d2[t2].x) t2++;
if(t1 <= n1 && t2 <= n2 && d1[t1].x == d2[t2].x){
mapto[d1[t1].id] = vto2[d2[t2].id];
t1++;
t2++;
}
}
nnod = 0;
T[0] = plant(1, n2);
queue<int>q;
while(!q.empty()) q.pop();
q.push(1);
while(!q.empty()){
int now = q.front();
q.pop();
if(mapto[now] == 0) T[now] = T[fa1[now]];
else T[now] = update(T[fa1[now]], mapto[now], 1, n2, +1);
for(int i = 0; i < v1[now].size(); i++){
int to = v1[now][i];
q.push(to);
}
}
int m;
scanf("%d",&m);
for(int im = 1; im <= m; im++){
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
lca1 = lca(l1, r1, lc1, dep1, fa1);
lca2 = lca(l2, r2, lc2, dep2, fa2);
int ans = jump(l2, lca2, true) + jump(r2, lca2, false);
printf("%d\n",ans);
}
}
return 0;
}
离线树状数组+树链剖分(平均2300ms。。)
离线树状数组+树链剖分(平均2300ms。。)
离线树状数组+树链剖分(平均2300ms。。)
离线树状数组+树链剖分(平均2300ms。。)
//Hello. I'm Peter.
#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<ctime>
#include<queue>
#include<set>
using namespace std;
typedef long long ll;
#define N 100010
int n1, n2, w1[N], w2[N], mapto[N], m;
struct Data{
int x, id;
}d1[N], d2[N];
bool cmp1(const Data a, const Data b){
return a.x < b.x;
}
struct Edge{
int fr, to, next;
}e1[N], e2[N];
int h1[N], h2[N], ne1, ne2;
void add(int fr, int to, Edge *e, int *h, int &ne){
int t = ++ne;
e[t].fr = fr, e[t].to = to;
e[t].next = h[fr], h[fr] = t;
}
void read(int *w, int &n, Edge *e, int *h, int &ne){
if(scanf("%d",&n) == EOF) exit(0);
for(int i = 1; i <= n; i++) h[i] = -1;
ne = 0;
for(int i = 2; i <= n; i++){
int f; scanf("%d",&f);
add(f, i, e, h, ne);
}
for(int i = 1; i <= n; i++){
scanf("%d", w + i);
}
}
int dep2[N], maxidep2, fa2[N], num2[N];
void dfs2(int now){
maxidep2 = max(maxidep2, dep2[now]);
num2[now] = 1;
for(int i = h2[now]; i != -1; i = e2[i].next){
int to = e2[i].to;
fa2[to] = now;
dep2[to] = dep2[now] + 1;
dfs2(to);
num2[now] += num2[to];
}
}
int vto2[N], upto2[N], dfsclock2;
void dfs3(int now){
vto2[now] = ++dfsclock2;
int w = -1, maxi = -1;
for(int i = h2[now]; i != -1; i = e2[i].next){
int to = e2[i].to;
if(num2[to] > maxi){
maxi = num2[to];
w = to;
}
}
if(w != -1){
upto2[w] = upto2[now];
dfs3(w);
}
for(int i = h2[now]; i != -1; i = e2[i].next){
int to = e2[i].to;
if(to == w) continue;
upto2[to] = to;
dfs3(to);
}
}
#define M 18
int lc2[N][M], lc1[N][M];
void init(int *fa, int lc[][M], int maxidep, int n){
for(int i = 1; i <= n; i++) lc[i][0] = fa[i];
for(int j = 1; 1<<j <= maxidep; j++){
for(int i = 1; i <= n; i++){
if(lc[i][j-1] != 0) lc[i][j] = lc[ lc[i][j-1] ][j-1];
else lc[i][j] = 0;
}
}
}
int lca(int a,int b, int *dep, int lc[][M], int *fa){
if(a == b) return a;
if(dep[a] < dep[b]) swap(a, b);
int log;
for(log = 0; 1<<log <= dep[a]; log++);
log--;
for(int i = log; i >= 0; i--){
if(lc[a][i] != 0 && dep[lc[a][i]] >= dep[b]) a = lc[a][i];
}
if(a == b) return a;
for(int i = log; i >= 0; i--){
if(lc[a][i] != lc[b][i]){
a = lc[a][i];
b = lc[b][i];
}
}
return fa[a];
}
int vto1[N], dfsclock1, fa1[N], dep1[N], maxidep1;
void dfs1(int now){
vto1[now] = ++dfsclock1;
maxidep1 = max(maxidep1, dep1[now]);
for(int i = h1[now]; i != -1; i = e1[i].next){
int to = e1[i].to;
fa1[to] = now;
dep1[to] = dep1[now] + 1;
dfs1(to);
}
}
int bit[N];
void update(int x, int v){
if(x == 0) return;
for(int i = x; i <= n2; i += i & -i){
bit[i] += v;
}
}
int query(int x){
int ans = 0;
for(int i = x; i > 0; i -= i & -i){
ans += bit[i];
}
return ans;
}
int jump(int now, int to, bool ach){
int ans = 0;
while(true){
if(ach && dep2[now] < dep2[to]) break;
else if(!ach && dep2[now] <= dep2[to]) break;
if(dep2[upto2[now]] <= dep2[to]){
if(ach) ans += query(vto2[now]) - query(vto2[to] - 1);
else ans += query(vto2[now]) - query(vto2[to] + 1 - 1);
break;
}
ans += query(vto2[now]) - query(vto2[upto2[now]] - 1);
now = fa2[upto2[now]];
}
return ans;
}
struct Query{
int l1, r1, l2, r2, lca2, lca1, falca1;
int ans, id;
}q[N];
bool cmp2(const Query a, const Query b){
return vto1[a.l1] < vto1[b.l1];
}
bool cmp3(const Query a, const Query b){
return vto1[a.r1] < vto1[b.r1];
}
bool cmp4(const Query a, const Query b){
return vto1[a.lca1] < vto1[b.lca1];
}
bool cmp5(const Query a, const Query b){
return vto1[a.falca1] < vto1[b.falca1];
}
bool cmp6(const Query a, const Query b){
return a.id < b.id;
}
int t;
void dfs4(int now, int ty){
update(mapto[now], +1);
while(ty == 1 && t <= m && q[t].l1 == now){
q[t].ans += jump(q[t].l2, q[t].lca2, true) + jump(q[t].r2, q[t].lca2, false);
t++;
}
while(ty == 2 && t <= m && q[t].r1 == now){
q[t].ans += jump(q[t].l2, q[t].lca2, true) + jump(q[t].r2, q[t].lca2, false);
t++;
}
while(ty == 3 && t <= m && q[t].lca1 == now){
q[t].ans -= jump(q[t].l2, q[t].lca2, true) + jump(q[t].r2, q[t].lca2, false);
t++;
}
while(ty == 4 && t <= m && q[t].falca1 == 0) t++;
while(ty == 4 && t <= m && q[t].falca1 == now){
q[t].ans -= jump(q[t].l2, q[t].lca2, true) + jump(q[t].r2, q[t].lca2, false);
t++;
}
for(int i = h1[now]; i != -1; i = e1[i].next){
int to = e1[i].to;
dfs4(to, ty);
}
update(mapto[now], -1);
}
int main(){
for(int kase = 1; ; kase++){
read(w1, n1, e1, h1, ne1);
read(w2, n2, e2, h2, ne2);
fa2[1] = 0;
dep2[1] = maxidep2 = 0;
dfs2(1);
upto2[1] = 1;
dfsclock2 = 0;
dfs3(1);
fa1[1] = 0;
dep1[1] = maxidep1 = 0;
dfsclock1 = 0;
dfs1(1);
init(fa1, lc1, maxidep1, n1);
init(fa2, lc2, maxidep2, n2);
for(int i = 1; i <= n1; i++){
d1[i].x = w1[i], d1[i].id = i;
}
sort(d1 + 1, d1 + 1 + n1, cmp1);
for(int i = 1; i <= n2; i++){
d2[i].x = w2[i], d2[i].id = i;
}
sort(d2 + 1, d2 + 1 + n2, cmp1);
for(int i = 0; i <= n1; i++) mapto[i] = 0;
int t1 = 1, t2 = 1;
while(t1 <= n1 && t2 <= n2){
while(t1 <= n1 && t2 <= n2 && d1[t1].x < d2[t2].x) t1++;
while(t1 <= n1 && t2 <= n2 && d1[t1].x > d2[t2].x) t2++;
if(t1 <= n1 && t2 <= n2 && d1[t1].x == d2[t2].x){
mapto[d1[t1].id] = vto2[d2[t2].id];
t1++, t2++;
}
}
scanf("%d",&m);
for(int i = 1; i <= m; i++){
scanf("%d%d%d%d",&q[i].l1,&q[i].r1,&q[i].l2,&q[i].r2);
q[i].lca1 = lca(q[i].l1, q[i].r1, dep1, lc1, fa1);
q[i].falca1 = fa1[q[i].lca1];
q[i].lca2 = lca(q[i].l2, q[i].r2, dep2, lc2, fa2);
q[i].id = i;
q[i].ans = 0;
}
for(int ty = 1; ty <= 4; ty++){
for(int i = 1; i <= n2; i++) bit[i] = 0;
if(ty == 1) sort(q + 1, q + 1 + m, cmp2);
else if(ty == 2) sort(q + 1, q + 1 + m, cmp3);
else if(ty == 3) sort(q + 1, q + 1 + m, cmp4);
else sort(q + 1, q + 1 + m, cmp5);
t = 1;
dfs4(1, ty);
}
sort(q + 1, q + 1 + m, cmp6);
for(int i = 1; i <= m; i++) printf("%d\n",q[i].ans);
}
return 0;
}