HDU 4822 Tri-war

来源:互联网 发布:最大的网络直播平台 编辑:程序博客网 时间:2024/04/30 03:55

Tri-war

Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 120 Accepted Submission(s): 33


Problem Description
Three countries, Red, Yellow, and Blue are in war. The map of battlefield is a tree, which means that there are N nodes and (N – 1) edges that connect all the nodes. Each country has a base station located in one node. All three countries will not place their station in the same node. And each country will start from its base station to occupy other nodes. For each node, country A will occupy it iff other two country's base stations have larger distances to that node compared to country A. Note that each edge is of the same length.

Given three country's base station, you task is to calculate the number of nodes each country occupies (the base station is counted).

Input
The input starts with a single integer T (1 ≤ T ≤ 10), the number of test cases.

Each test cases starts with a single integer N (3 ≤ N ≤ 10 ^ 5), which means there are N nodes in the tree.

Then N - 1 lines follow, each containing two integers u and v (1 ≤ u, v ≤ N, u ≠ v), which means that there is an edge between node u and node v.

Then a single integer M (1 ≤ M ≤ 10 ^ 5) follows, indicating the number of queries.

Each the next M lines contains a query of three integers a, b, c (1 ≤ a, b, c ≤ N, a, b, c are distinct), which indicates the base stations of the three countries respectively.

Output
For each query, you should output three integers in a single line, separated by white spaces, indicating the number of nodes that each country occupies. Note that the order is the same as the country's base station input.

Sample Input
191 21 31 42 52 62 76 86 921 2 82 1 4

Sample Output
3 3 16 2 1

Source
2013 Asia Regional Changchun

Recommend
liuyiding



题意:有一棵树,每条边的长度是一样的,每次询问三个互不相同的点分别在整棵树中有多少个点是属于它的,点A属于点B当且仅当A点到B的距离比到另外两个点的距离要小。


思路:首先考虑简单情况,假设只有两个点,那么很明显我们只要找到两个点路径的中点就行了,这样就能确定什么点会属于它们,但是我们要求三个点的情况,其实我们可以分开考虑,假设那三个点是A,B,C,那么我们只需要考虑将A在B的影响下,能取到的子树和A在C的影响下能取到的子树做个交集就行了,因为这一部分是B和C都无法取到的,而A可以取。 然后交集的计算我用的是线段树,我们只需要将A在B影响下能取到的子树的每个点置为1,A在C影响下的子树求和就能得到有多少是相交的。


代码:

#include <iostream>#include <cstdio>#include <cstring>#include <cassert>#include <algorithm>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define rep(i,a,b) for(int i=(a);i<(int)(b);++i)#define rrep(i,b,a) for(int i=(b);i>=(int)(a);--i)#define clr(a,x) memset(a,x,sizeof(a))#pragma comment(linker,"/STACK:102400000,102400000")const int maxn = 100000+5;int col[maxn<<2],sum[maxn<<2];void read_int(int & x){//    cin>>x; return;    char ch=getchar();    while(ch<'0'||ch>'9') ch=getchar();    x=ch-'0'; ch=getchar();    while('0'<=ch&&ch<='9') {        x=x*10+ch-'0';        ch = getchar();    }}void PushDown(int l,int r,int m,int rt){    if (col[rt]!=-1) {        sum[rt<<1] = col[rt] * (m-l+1);        sum[rt<<1|1] = col[rt] * (r-m);        col[rt<<1] = col[rt<<1|1] = col[rt];        col[rt] = -1;    }}void PushUp(int rt) { sum[rt] = sum[rt<<1]+sum[rt<<1|1]; }int query(int L,int R,int l,int r,int rt){    if (l > r) return 0;    if (L<=l&&r<=R) return sum[rt];    int m = (l+r)>>1;    PushDown(l,r,m,rt);    int ret = 0;    if (L<=m) ret += query(L,R,lson);    if (m<R) ret += query(L,R,rson);    PushUp(rt);    return ret;}void update(int L,int R,int x,int l,int r,int rt){    if (l > r) return;    if (L<=l&&r<=R) {        col[rt] = x;        sum[rt] = x*(r-l+1);        return;    }    int m = (l+r)>>1;    PushDown(l,r,m,rt);    if(L<=m) update(L,R,x,lson);    if(m<R) update(L,R,x,rson);    PushUp(rt);}int dep[maxn],anc[maxn][20];int clk,L[maxn],R[maxn];struct Node{    int v;    Node * next;}*first[maxn],edges[maxn*2];int ptr;void add(int u,int v){    edges[++ptr].v = v;    edges[ptr].next = first[u];    first[u] = &edges[ptr];}int n;void input(){    clr(first,0); ptr = 0;    scanf("%d",&n);    rep(i,0,n-1) {        int u,v;        read_int(u); read_int(v);        add(u,v); add(v,u);    }}void dfs(int u,int fa,int d){    anc[u][0] = fa;    L[u] = ++clk;    for(Node * p=first[u];p;p=p->next) {        int v = p->v;        if(v==fa) continue;        dep[v] = dep[u] + 1;        dfs(v,u,d+1);    }    R[u] = clk;}void build_rmq(){    for(int j=1;(1<<j)<n;++j)    for(int i=1;i<=n;++i) if(anc[i][j-1]!=-1) {        int a = anc[i][j-1];        anc[i][j] = anc[a][j-1];    }}int Up(int a,int d){    int j = 0;    while (d > 0) {        if (d & 1) a = anc[a][j];        ++j; d >>= 1;    }    return a;}int Lca(int p,int q){    if(dep[p]<dep[q]) swap(p,q);    p = Up(p,dep[q]-dep[p]);    if(p==q) return p;    int log = 0;     while ((1<<log) <= dep[p]) ++log; --log;    for(int i=log;i>=0;--i)    if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i]) {        p=anc[p][i];        q=anc[q][i];    }    return anc[q][0];}int Query(int a,int b,int c){    int ab = Lca(a,b),ac = Lca(a,c);    int ret = 0;    if (dep[a] >= dep[b]) {        int d = dep[a] + dep[b] - 2 * dep[ab];        int aa = Up(a,(d-1)/2);        update(L[aa],R[aa],1,1,n,1);    } else {        int d = dep[a] + dep[b] - 2 * dep[ab];        int bb = Up(b,d/2);        update(1,L[bb]-1,1,1,n,1);        update(R[bb]+1,n,1,1,n,1);    }    b = c; ab = ac;    if (dep[a] >= dep[b]) {        int d = dep[a] + dep[b] - 2 * dep[ab];        int aa = Up(a,(d-1)/2);        ret += query(L[aa],R[aa],1,n,1);    } else {        int d = dep[a] + dep[b] - 2 * dep[ab];        int bb = Up(b,d/2);        ret += query(1,L[bb]-1,1,n,1);        ret += query(R[bb]+1,n,1,n,1);    }    return ret;}void solve(){    clk = 0;    dep[1] = 0;    clr(anc,-1);    dfs(1,-1,0);    clr(col,-1);    update(1,n,1,1,n,1);    build_rmq();    int M; scanf("%d",&M);    while (M--) {        update(1,n,0,1,n,1);        int a,b,c;        read_int(a); read_int(b); read_int(c);        printf("%d %d %d\n",Query(a,b,c),Query(b,a,c),Query(c,b,a));    }}int main(){    int T; cin >> T;    while (T--) {        input();        solve();    }}


0 0
原创粉丝点击