HDU 5111((离线树状数组 or 主席树)+树链剖分)

题意:给两棵树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;
}

你可能感兴趣的:(树状数组,树链剖分,主席树)