【Luogu P4149】[IOI2011]Race(點分治)

自閉了幾天後的我終於開始作題了。。而後調了3h一道點分治板子題,調了一天一道IOI。。。git

最後仍是本身手造數據debug出來的。。。spa

這題一看:樹上路徑問題,已知路徑長度求balabala,顯然是點分治(其實只要有一點點對點分治思想及應用的理解就能知道)。照普通點分治的作法,找重心分治,每次統計子樹全部點到根的距離,而後開個桶判斷一下是否出現便可(本題還要存一下邊數)。而後咱們要作的只有暴力統計取min了,時間複雜度\(O(n\log n)\)debug

因而本蒟蒻自信滿滿地打下了如下代碼:code

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 202000
#define maxk 10001000
struct edge {
    int w, to, next;
} e[maxn << 1];
int head[maxn], dis[maxn], save[maxn], save2[maxn], cnt[maxn], vis[maxn], size[maxn], maxp[maxn], ecnt, sum, depth[maxn];
int get[maxk], get2[maxk];
int n, m, k, ans = 0x3f3f3f3f;
#define isdigit(x) ((x) >= '0' && (x) <= '9')
inline int read() {
    int res = 0;
    char c = getchar();
    while (!isdigit(c)) c = getchar();
    while (isdigit(c)) res = (res << 1) + (res << 3) + (c ^ 48), c = getchar();
    return res;
}
void adde(int u, int v, int w) {
    e[++ecnt] = (edge) {w, v, head[u]};
    head[u] = ecnt;
}
int getrt(int x, int fa) {
    int rt = 0;
    maxp[x] = 0;
    size[x] = 1;
    for (int i = head[x]; i; i = e[i].next) {
        int to = e[i].to;
        if (vis[to] || to == fa) continue;
        rt = getrt(to, x);
        size[x] += size[to];
        maxp[x] = max(maxp[x], size[to]);
    }
    maxp[x] = max(maxp[x], sum - size[x]);
    if (maxp[rt] > maxp[x]) rt = x;
    return rt;
}
void getdis(int x, int fa) {
    save[++save[0]] = dis[x];
    cnt[++cnt[0]] = depth[x];
    for (int i = head[x]; i; i = e[i].next) {
        int to = e[i].to;
        if (vis[to] || to == fa) continue;
        dis[to] = dis[x] + e[i].w;
        depth[to] = depth[x] + 1;
        getdis(to, x);
    }
}
void work(int x) {
    save2[0] = 0;
    for (int i = head[x]; i; i = e[i].next) {
        int to = e[i].to;
        if (vis[to]) continue;
        save[0] = cnt[0] = 0;
        dis[to] = e[i].w;
        depth[to] = 1;
        getdis(to, x);
        
        for (int j = 1; j <= save[0]; ++j) {
        //  get2[save[j]] = min(get2[save[j]], cnt[j]);
            if (k >= save[j] && get[k - save[j]])
                ans = min(ans, get2[k - save[j]] + cnt[j]);
        }
            
        for (int j = 1; j <= save[0]; ++j) {
            get[save[j]] = 1, save2[++save2[0]] = save[j];
            get2[save[j]] = min(get2[save[j]], cnt[j]);
        }
    }
    for (int i = 1; i <= save2[0]; ++i) get[save2[i]] = 0, get2[save2[i]] = 0x3f3f3f3f;
}
void dfs(int x) {
    vis[x] = get[0] = 1;
    get2[0] = 0;
    work(x);
    for (int i = head[x]; i; i = e[i].next) {
        int to = e[i].to;
        if (vis[to]) continue;
        maxp[0] = n;
        sum = size[to];
        dfs(getrt(to, 0));
    }
}
int main() {
    memset(get2, 0x3f, sizeof(get2));
    n = read(), k = read();
    for (int i = 1; i < n; ++i) {
        int u = read(), v = read(), w = read();
        adde(u + 1, v + 1, w);
        adde(v + 1, u + 1, w);
    }
    maxp[0] = sum = n;
    dfs(getrt(1, 0));
    if (ans == 0x3f3f3f3f) puts("-1");
    else printf("%d\n", ans);
    return 0;
}

RE85。爆棧?算了就算爆棧如今除了重寫一遍也沒有別的解決辦法了。。get

嘗試把兩個桶開大2倍,變成90了。string

再開大2倍,變成MLE了。看來是數據太大,桶開不下。因而寫了個unordered_map,常數極大,TLE到只有20分。it

回過頭來,發現save裏存的路徑長度只有\(≤k\)時纔對答案有貢獻,不符合條件的均可以不存進桶裏,桶能夠只開到1e6多一點(保證k不越界就行)。加一句特判便可AC。io

code:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 200007
#define maxk 1000007
struct edge {
    int w, to, next;
} e[maxn << 1];
int head[maxn], dis[maxn], save[maxn], save2[maxn], cnt[maxn], vis[maxn], size[maxn], maxp[maxn], ecnt, sum, depth[maxn];
int get[maxk], get2[maxk];
int n, m, k, ans = 0x3f3f3f3f;
#define isdigit(x) ((x) >= '0' && (x) <= '9')
inline int read() {
    int res = 0;
    char c = getchar();
    while (!isdigit(c)) c = getchar();
    while (isdigit(c)) res = (res << 1) + (res << 3) + (c ^ 48), c = getchar();
    return res;
}
void adde(int u, int v, int w) {
    e[++ecnt] = (edge) {w, v, head[u]};
    head[u] = ecnt;
}
int getrt(int x, int fa) {
    int rt = 0;
    maxp[x] = 0;
    size[x] = 1;
    for (int i = head[x]; i; i = e[i].next) {
        int to = e[i].to;
        if (vis[to] || to == fa) continue;
        rt = getrt(to, x);
        size[x] += size[to];
        maxp[x] = max(maxp[x], size[to]);
    }
    maxp[x] = max(maxp[x], sum - size[x]);
    if (maxp[rt] > maxp[x]) rt = x;
    return rt;
}
void getdis(int x, int fa) {
    save[++save[0]] = dis[x];
    cnt[++cnt[0]] = depth[x];
    for (int i = head[x]; i; i = e[i].next) {
        int to = e[i].to;
        if (vis[to] || to == fa) continue;
        dis[to] = dis[x] + e[i].w;
        depth[to] = depth[x] + 1;
        getdis(to, x);
    }
}
void work(int x) {
    save2[0] = 0;
    for (int i = head[x]; i; i = e[i].next) {
        int to = e[i].to;
        if (vis[to]) continue;
        save[0] = cnt[0] = 0;
        dis[to] = e[i].w;
        depth[to] = 1;
        getdis(to, x);
        
        for (int j = 1; j <= save[0]; ++j) {
        //  get2[save[j]] = min(get2[save[j]], cnt[j]);
            if (k >= save[j] && get[k - save[j]])
                ans = min(ans, get2[k - save[j]] + cnt[j]);
        }
            
        for (int j = 1; j <= save[0]; ++j) 
            if (save[j] <= k) {
                get[save[j]] = 1, save2[++save2[0]] = save[j];
                get2[save[j]] = min(get2[save[j]], cnt[j]);
            }
    }
    for (int i = 1; i <= save2[0]; ++i) get[save2[i]] = 0, get2[save2[i]] = 0x3f3f3f3f;
}
void dfs(int x) {
    vis[x] = get[0] = 1;
    get2[0] = 0;
    work(x);
    for (int i = head[x]; i; i = e[i].next) {
        int to = e[i].to;
        if (vis[to]) continue;
        maxp[0] = n;
        sum = size[to];
        dfs(getrt(to, 0));
    }
}
int main() {
    memset(get2, 0x3f, sizeof(get2));
    n = read(), k = read();
    for (int i = 1; i < n; ++i) {
        int u = read(), v = read(), w = read();
        adde(u + 1, v + 1, w);
        adde(v + 1, u + 1, w);
    }
    maxp[0] = sum = n;
    dfs(getrt(1, 0));
    if (ans == 0x3f3f3f3f) puts("-1");
    else printf("%d\n", ans);
    return 0;
}
相關文章
相關標籤/搜索