UVALive 7148 LRIP(树分治+STL)

来源:互联网 发布:linux 文件夹访问权限 编辑:程序博客网 时间:2024/06/04 18:05

题目链接

题目大意:给出一棵树有1n105个节点,每个节点有个权值1ai105,求一个由节点构成的
最长权值不降连续子串,且串的最大值和最小值的差diffD,1D105,样例数T10
思路:用树分治比较方便。考虑这条路径经过根和不经过根两种情况;不经过根就到其子树中去找,
经过根就得先维护一个上升串(离根越远值越小),然后在下降串中每次到上升串中二分即可。
在上升串中,如果dep[u]dep[v]&&val[u]val[v],那么u在任何时候都不会比v差,那么v就可以删除掉。
另外一份讲解

int nCase = 0;const int maxn = 1e5 + 123;int n, D;vector<int> G[maxn], nodes;bool del[maxn];int size[maxn], maxBranch[maxn];int val[maxn];int ans;/*找到每棵树的中心根*/void dfs(int u,int f) {    size[u] = 1, maxBranch[u] = 0;    for (int v : G[u]) {        if (v != f && !del[v]) {            dfs(v, u);            size[u] += size[v];            maxBranch[u] = max(maxBranch[u], size[v]);        }    }    nodes.push_back(u);}int findRoot(int u) {    nodes.clear();    dfs(u, -1);    int rt = u;    for (int v : nodes) {        maxBranch[v] = max(maxBranch[v], size[u] - size[v]);        if (maxBranch[v] < maxBranch[rt]) {            rt = v;        }    }    return rt;}map<int, int> up;/*更新up值,如果dep[u] >= dep[v] && val[u] >= val[v],那么v在任何时候都不会比u优*/void updata(int v, int len) {    auto x = up.lower_bound(v);    if (x != up.end() && x->second >= len) return ;    auto ed = up.upper_bound(v);    auto it = map<int, int> :: reverse_iterator(ed);/*反着找*/    while(it != up.rend() && it->second <= len) it++;    up.erase(it.base(), ed);    up[v] = len;}void dfs_up(int u,int f,int depth) {    updata(val[u], depth);    for (int v : G[u])         if (!del[v] && v != f && val[v] <= val[u]) dfs_up(v, u, depth + 1);}void dfs_down(int u,int f,int depth) {    auto it = up.lower_bound(val[u] - D);    if (it != up.end()) ans = max(ans, it->second + depth + 1);    for (int v : G[u]) {        if (!del[v] && v != f && val[v] >= val[u]) dfs_down(v, u, depth + 1);    }}void _work(int u,vector<int>& son) {    up.clear();    up[val[u]] = 0;    for (int v : son) {        if (val[v] >= val[u]) dfs_down(v, u, 1);        if (val[v] <= val[u]) dfs_up(v, u, 1);    }}void work(int u) {    vector<int> son;    for (int v : G[u])        if (!del[v]) son.push_back(v);    _work(u, son);    /*反转一次继续找,因为对于以v为根的子树求的上升值是其前面的子树形成的结果*/    /*还有可能是其后面的子树更优,所以要反转继续找*/    reverse(ALL(son));    _work(u, son);}void solve(int u) {    u = findRoot(u);    vector<int> son;    work(u);    del[u] = true;    for (int v : G[u])        if (!del[v]) solve(v);}int main(int argc, const char * argv[]){        // freopen("in.txt","r",stdin);    // freopen("out.txt","w",stdout);    // ios::sync_with_stdio(false);    // cout.sync_with_stdio(false);    // cin.sync_with_stdio(false);    int kase;cin >> kase;    while(kase--) {        cin >> n >> D;        Rep(i, 1, n) G[i].clear();        memset(del + 1, false, n * sizeof (bool));        Rep(i, 1, n) scanf("%d", &val[i]);        int u, v;        Rep(i, 1, n - 1) {            scanf("%d%d", &u, &v);            G[u].push_back(v);            G[v].push_back(u);        }        ans = 1;        solve(1);        printf("Case #%d: %d\n", ++nCase, ans);    }    // showtime;    return 0;}
0 0
原创粉丝点击