【算法练习】POJ - 2114 Boatherds(点分治)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pengwill97/article/details/82562978

题意

给出一棵树,一些询问,询问树上是否有路径和为k的路径。

题解

发现询问只有100个,依次处理询问即可。

代码

这里依旧给出了两种写法, 一种是排序后利用单调性,一种是排序后二分。
利用单调性常数更小。
如果利用单调性,函数要返回 c n t << 1 。因为认为u到v和v到u是不同路径。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
struct edge {
    int to, nxt, w;
}e[10005 << 1];
int head[10005], tot;
void add_edge(int u, int v, int  w) {
    e[tot].to = v;
    e[tot].nxt = head[u];
    e[tot].w = w;
    head[u] = tot++;
}
int n, m;
int sz[10005], root, nowmx, totnode, k, ans;
bool visit[10005];
void getroot(int u, int f) {
    sz[u] = 1;
    int mxpart = 0;
    for(int i = head[u]; i != -1; i = e[i].nxt) {
        int v = e[i].to;
        if(v != f && !visit[v]) {
            getroot(v, u);
            sz[u] += sz[v];
            mxpart = max(mxpart, sz[v]);
        }
    }
    mxpart = max(mxpart, totnode - sz[u]);
    if(mxpart < nowmx) {
        nowmx = mxpart;
        root  = u;
    }
}
int ss[10005], top;
void dfs(int u, int f, int d) {
    if(d > k)
        return;
    ss[++top] = d;
    for(int i = head[u]; i != -1; i = e[i].nxt) {
        int v = e[i].to;
        if(v != f && !visit[v]) {
            dfs(v, u, d + e[i].w);
        }
    }
}
int getans(int u, int init) {
    top = 0;
    int cnt = 0;
    dfs(u, u, init);
    sort(ss + 1, ss + 1 + top);
    int l = 1, r = top;
    while(l < r) {
        if(ss[l] + ss[r] > k) r --;
        else if(ss[l] + ss[r] < k) l ++;
        else {
            if(ss[l] == ss[r]) {
                cnt += (r - l + 1) * (r - l) /2;
                break;
            } else {
                int i = l, j = r;
                while(ss[l] == ss[i]) i++;
                while(ss[r] == ss[j]) j--;
                int tmp = (i - l) * (r - j);
                cnt += tmp;
                l = i;
                r = j;
            }
        }
    }
//    }
//    int mid = (top + 1)/ 2 ;
//    for(int i = 1; i <= top; ++i)
//        printf("%d ",ss[i]);
//    printf("\n");
//    for(int i = 1; i <= top; ++i) {
//        int posl = lower_bound(ss + 1, ss + 1 + top, k - ss[i]) - (ss);
//        int posr = upper_bound(ss + 1, ss + 1 + top, k - ss[i]) - (ss);
////        printf("debug %d %d %d\n", ss[i], posl, posr);
//        if(ss[i] + ss[posl] == k && ss[i] == ss[posl]) {
//            if(posr - posl - 1 > 0) {
//                cnt += posr - posl - 1;
////                printf("in %d %d\n",ss[i], posr - posl - 1);
//            }
//        } else if(ss[i] + ss[posl] == k) {
//            cnt += posr - posl;
////            printf("in %d %d\n",ss[i], posr - posl + 1);
//        }
//    }
    return cnt;
}
void solve(int u) {
    ans += getans(u, 0);
    visit[u] = true;
    for(int i = head[u]; i != -1; i = e[i].nxt) {
        int v = e[i].to;
        if(!visit[v]) {
            ans -= getans(v, e[i].w);
            nowmx = INF; root = 0; totnode = sz[v];
            getroot(v, u);
            solve(root);
        }
    }
}
int main(){
    while(scanf("%d", &n) && n) {
        memset(head, -1, sizeof head);
        tot = 0;
        for(int i = 1 ; i <= n; ++i) {
            int v, w;
            while(scanf("%d", &v) && v) {
                scanf("%d", &w);
                add_edge(i, v, w);
                add_edge(v, i ,w);
            }
        }
        while(scanf("%d", &k) && k) {
            ans = 0; totnode = n; nowmx = INF; root = 0;
            memset(visit, 0, sizeof visit);
            getroot(1, -1);
            solve(root);
            if(ans == 0) printf("NAY\n");
            else printf("AYE\n");
        }
        printf(".\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/pengwill97/article/details/82562978