HDU4822-Tri-War

题目

给出一颗树,\(m\)次询问树上不相同的三个点\(A,B,C\)。我们称一个点\(x\)\(A\)占领当且仅当\(dist(A,x)>dist(B,x),dist(A,x)>dist(C,x)\)

\(A,B,C\)这三个点分别占领了多少个点。

\(n,m\le 10^5\)

分析

如果是两个点的话,我们找到他们的中点,讨论一下即可。现在有三个点,那么我们对\(A\),分别算一下与\(B\)\(C\)的dfn序区间,用线段树做一下区间求交即可。也可以扫描线求交,不过最多就四个区间。

代码

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
int read() {
    int x=0,f=1;
    char c=getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=1e5+1;
const int maxj=17;
int f[maxn][maxj],dep[maxn],dfx,first[maxn],second[maxn],n;
struct TREE {
    vector<int> g[maxn];
    inline void clear(int n) {
        memset(f,0,sizeof f),memset(dep,0,sizeof dep);
        memset(first,0,sizeof first),memset(second,0,sizeof second);
        for (int i=1;i<=n;++i) g[i].clear();
        dfx=0;
    }
    inline void add(int x,int y) {g[x].push_back(y);}
    void dfs(int x,int fa) {
        f[x][0]=fa;
        dep[x]=dep[fa]+1;
        first[x]=++dfx;
        for (int v:g[x]) if (v!=fa) dfs(v,x);
        second[x]=dfx;
    }
    void run() {
        dfs(1,1);
        for (int j=1;j<maxj;++j) for (int i=1;i<=n;++i) f[i][j]=f[f[i][j-1]][j-1];
    }
    int lca(int x,int y) {
        if (dep[x]<dep[y]) swap(x,y);
        for (int j=maxj-1;j>=0;--j) if (dep[f[x][j]]>=dep[y]) x=f[x][j];
        if (x==y) return x;
        for (int j=maxj-1;j>=0;--j) if (f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j];
        return f[x][0];
    }
    int jump(int x,int y) {
        for (int j=maxj-1;j>=0;--j) if ((y>>j)&1) x=f[x][j];
        return x;
    }
} tree;
struct SGT {
    struct node {
        int zero,one,two,tag;
        int tic;
    } t[maxn<<2];
    int tim;
    SGT ():tim(0) {}
    void flow() {++tim;}
    void doit(int x) {
        t[x].two=t[x].one,t[x].one=t[x].zero,t[x].zero=0;
        ++t[x].tag;
    }
    void pushdown(int x,int L,int mid,int R) {
        newnode(x<<1,L,mid),newnode(x<<1|1,mid+1,R);
        for (int &tmp=t[x].tag;tmp;--tmp) doit(x<<1),doit(x<<1|1);
    }
    void update(int x,int L,int mid,int R) {
        newnode(x<<1,L,mid),newnode(x<<1|1,mid+1,R);
        t[x].zero=t[x<<1].zero+t[x<<1|1].zero;
        t[x].one=t[x<<1].one+t[x<<1|1].one;
        t[x].two=t[x<<1].two+t[x<<1|1].two;
    }
    void newnode(int x,int L,int R) {
        if (t[x].tic!=tim) t[x].tic=tim,t[x].one=t[x].two=0,t[x].zero=R-L+1,t[x].tag=0;
    }
    void inc(int x,int L,int R,int l,int r) {
        newnode(x,L,R);
        if (L==l && R==r) {
            doit(x);
            return;
        }
        int mid=(L+R)>>1;
        pushdown(x,L,mid,R);
        if (r<=mid) inc(x<<1,L,mid,l,r); else
        if (l>mid) inc(x<<1|1,mid+1,R,l,r); else 
        inc(x<<1,L,mid,l,mid),inc(x<<1|1,mid+1,R,mid+1,r);
        update(x,L,mid,R);
    }
    void inc(int l,int r) {
        if (l>r) return;
        inc(1,1,n,l,r);
    }
    int query() {
        return t[1].two;
    }
} sgt;
void deal(int a,int b) {
    int l=tree.lca(a,b);
    if (a==l) {
        int d=dep[b]-dep[a];
        int jp=d>>1;
        int p=tree.jump(b,jp);
        sgt.inc(1,first[p]-1);
        sgt.inc(second[p]+1,n);
    } else if (b==l) {
        int d=dep[a]-dep[b];
        int jp=(d-1)>>1;
        int p=tree.jump(a,jp);
        sgt.inc(first[p],second[p]);
    } else {
        int ad=dep[a]-dep[l],bd=dep[b]-dep[l];
        if (ad==bd) {
            int p=tree.jump(a,ad-1);
            sgt.inc(first[p],second[p]);
        } else if (ad>bd) {
            int d=ad+bd,jp=(d-1)>>1;
            int p=tree.jump(a,jp);
            sgt.inc(first[p],second[p]);
        } else if (ad<bd) {
            int d=ad+bd,jp=d>>1;
            int p=tree.jump(b,jp);
            sgt.inc(1,first[p]-1);
            sgt.inc(second[p]+1,n);
        }
    }
}
int Ans(int a,int b,int c) {
    sgt.flow();
    deal(a,b);
    deal(a,c);
    return sgt.query();
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
#endif
    int T=read();
    while (T--) {
        n=read();
        tree.clear(n);
        for (int i=1;i<n;++i) {
            int x=read(),y=read();
            tree.add(x,y),tree.add(y,x);
        }
        tree.run();
        int q=read();
        while (q--) {
            int fir=read(),sec=read(),thr=read();
            int afir=Ans(fir,sec,thr);
            int asec=Ans(sec,fir,thr);
            int athr=Ans(thr,fir,sec);
            printf("%d %d %d\n",afir,asec,athr);
        }
    }
    return 0;
}
posted @ 2017-07-10 15:41  permui  阅读(357)  评论(0编辑  收藏  举报