POJ2114 Boatherds 点分治

来源:互联网 发布:小甲鱼python解压密码 编辑:程序博客网 时间:2024/05/22 12:06
/*    题目描述:给定一棵有n(0 < n < 1e4)个节点的树,给出不超过100个询问,对于每次询问给出一个x,问树中是否存在点对之间的                距离恰好为x                    方法:比较直接的点分治问题,与poj1741不同的地方是不能直接双指针来扫,而是用二分来查找统计和恰好为x的点对,复杂度            O(100 * n *logn * logn)*/#pragma warning(disable:4786)#pragma comment(linker, "/STACK:102400000,102400000")#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<stack>#include<queue>#include<map>#include<set>#include<vector>#include<cmath>#include<string>#include<sstream>#include<bitset>#define LL long long#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)#define mem(a,x) memset(a,x,sizeof(a))#define lson l,m,x<<1#define rson m+1,r,x<<1|1using namespace std;const int INF = 0x3f3f3f3f;const int mod = 1e9 + 7;const double PI = acos(-1.0);const double eps=1e-6;const int maxn = 1e4 + 5;int size[maxn] , maxv[maxn] , vis[maxn] , dis[maxn];int x[105] , cnt[105] , up[maxn] , low[maxn];int ans , root , Max , num ,n , m;int tot;int head[maxn] ;int lowbsearch(int left , int right , int val){    int mid , ret = -1;    while(left <= right){        mid = left + (right - left) / 2;        if(dis[mid] == val){            ret = mid;            right = mid - 1;        }        else if(dis[mid] > val)     right = mid - 1;        else    left = mid + 1;    }    return ret;}int upbsearch(int left , int right , int val){    int mid , ret = -1;    while(left <= right){        mid = left + (right - left) / 2;        if(dis[mid] == val){            ret = mid;            left = mid + 1;        }        else if(dis[mid] > val)     right = mid - 1;        else    left = mid + 1;    }    return ret;}struct node{    int v, w, nt;}edges[maxn * 2];void init(){    tot = 0;    mem(vis , 0);    mem(head , -1);}void add_edge(int u , int v , int w){    edges[tot].v = v;    edges[tot].w = w;    edges[tot].nt = head[u];    head[u] = tot++;}void dfssize(int u , int fa){    size[u] = 1;    maxv[u] = 0;    for(int i = head[u] ; i != -1 ; i = edges[i].nt){        int v = edges[i].v ;        if(vis[v] || v == fa)       continue;        dfssize(v , u);        size[u] += size[v];        maxv[u] = max(maxv[u] , size[v]);    }}void dfsroot(int r , int u , int fa){    if(size[r] - size[u] > maxv[u])     maxv[u] = size[r] - size[u];    if(maxv[u] < Max)   {        Max = maxv[u];        root = u;    }    for(int i = head[u] ; i!= -1 ; i = edges[i].nt){        int v = edges[i].v;        if(vis[v] || v == fa)       continue;        dfsroot(r , v , u);    }}void dfsdis(int u  , int d , int fa){    dis[num++] = d;    for(int i = head[u] ; i != -1 ; i = edges[i].nt){        int v = edges[i].v;        if(vis[v] || v == fa)       continue;        dfsdis(v , d + edges[i].w , u);    }}void calc(int u , int d , int sgn){    num = 0;    dfsdis(u , d , 0);    sort(dis , dis + num);    for(int k = 1 ; k<= m ; k++){        int i = 0 , j = num - 1;        for(i = 0 ; i < num - 1; i++){            if(dis[i] > x[k])       break;            int pos1 = lowbsearch(i + 1 , num - 1 , x[k] - dis[i]);            if(pos1 == -1)      continue;            int pos2 = upbsearch(i + 1 , num - 1 , x[k] - dis[i]);            cnt[k] += sgn * (pos2 - pos1 + 1);        }    }}void dfs(int u){    Max = n;    dfssize(u , 0);    dfsroot(u , u , 0);    calc(root , 0 , 1);    vis[root] = 1;    for(int i = head[root]; i !=- 1 ; i = edges[i].nt){        int v= edges[i].v;        if(!vis[v]){            calc(v , edges[i].w , -1);            dfs(v);        }    }}int main(){    while(scanf("%d" , &n) != EOF){        if(!n)      break;        m = 0;        mem(cnt , 0);        init();        int c , d , query;        for(int i = 1 ; i<= n ; i++){            while(scanf("%d" , &c) && c){                scanf("%d" , &d);                add_edge(i , c , d);                add_edge(c , i , d);            }        }        while(scanf("%d" , &query) && query != 0){            x[++m] = query;        }        dfs(1);        for(int i = 1 ; i<= m ; i++){            if(cnt[i])      puts("AYE");            else            puts("NAY");        }        puts(".");    }    return 0;}


0 0
原创粉丝点击