• SPOJ 1825


    我的树分治#3.

    After the success of 2nd anniversary (take a look at problem FTOUR for more details), this 3rd year, Travel Agent SPOJ goes on with another discount tour.

    The tour will be held on ICPC island, a miraculous one on the Pacific Ocean. We list N places (indexed from 1 to N) where the visitors can have a trip. Each road connecting them has an interest value, and this value can be negative (if there is nothing interesting to view there). Simply, these N places along with the roads connecting them form a tree structure. We will choose two places as the departure and destination of the tour.

    Since September is the festival season of local inhabitants, some places are extremely crowded (we call them crowded places). Therefore, the organizer of the excursion hopes the tour will visit at most K crowded places (too tiring to visit many of them) and of course, the total number of interesting value should be maximum.

    Briefly, you are given a map of N places, an integer K, and M id numbers of crowded place. Please help us to find the optimal tour. Note that we can visit each place only once (or our customers easily feel bored), also the departure and destination places don't need to be different.

    Input

    There is exactly one case. First one line, containing 3 integers N K M, with 1 <= N <= 200000, 0 <= K <= M, 0 <= M <= N.

    Next M lines, each line includes an id number of a crowded place.

    The last (N - 1) lines describe (N - 1) two-way roads connected N places, form a b i, with a, b is the id of 2 places, and i is its interest value (-10000 <= i <= 10000).

    Output

    Only one number, the maximum total interest value we can obtain.

    Example

    Input: 8 2 3
    3
    5
    7
    1 3 1
    2 3 10
    3 4 -2
    4 5 -1
    5 7 6
    5 6 5
    4 8 3 Output: 12
    

    Explanation

    We choose 2 and 6 as the departure and destination place, so the tour will be 2 -> 3 -> 4 -> 5 -> 6, total interest value = 10 + (-2) + (-1) + 5 = 12

    大意:

    给你一棵树, 每个点非白即黑,求树上黑点个数不超过k的路径的最长长度.

    做法:

    我们先考虑一个笨办法. 我们只需要合并不同的子树即可. 那么必须满足子树的根节点u != v.

    根据论文上的一个好办法. u != v  <=> u < v

    也即按序合并答案. 那么我们用一个树状数组来记录前缀最大值,那么我们就能够在O(nlog2n)的时间内解决这个问题.

    SPOJ卡得非常紧,必须O(nlogn)的算法.

    那么怎么做呢?

    我们考虑将不同的子树的里面的信息合并,那么也就是保留到当前根的路径上黑点为x的最长的路径.

    然后我们不断更新这个数组,并且在更新的时候计算一个前缀最大值数组.那么我们能够在O(黑点个数)的时间内统计出一个点为根的答案.

    注意到让孩子的黑点数有序操作会提高效率!

    这是因为对于一个存在黑点路径的子树,它所需要保留的外界的路径长度都是 k-1 然后如果孩子个数不有序,那么就每次都是O(最多黑点个数)的更新复杂度....

    最坏情况下是O(n2)的.

    但是如果孩子个数有序,那么就只有之前那个孩子大小的更新复杂度.

    总的算起来,就是O(n)的.

      1 #include<cstdlib>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<cctype>
      6 #ifdef WIN32
      7 #define fmt64 "%I64d"
      8 #else
      9 #define fmt64 "%lld"
     10 #endif
     11 using namespace std;
     12 const int maxn = (int)2.5e5, inf = 0x3f3f3f3f;
     13 struct E{
     14     int t,w,last;
     15 }e[maxn * 2];
     16 int last[maxn],edg;
     17 int n,m,k;
     18 int black[maxn];
     19 void add(int x,int y,int w){
     20     e[++edg] = (E){y,w,last[x]}; last[x] = edg;
     21     e[++edg] = (E){x,w,last[y]}; last[y] = edg;
     22 }
     23 int getint(){
     24     int ret = 0,t = 1; char ch = getchar();
     25     while(!isdigit(ch)) t = ch == '-' ? -1 : 1, ch = getchar();
     26     while(isdigit(ch)) ret = ret * 10 + ch - '0', ch = getchar();
     27     return ret * t;
     28 }
     29 int tmax,node,root;
     30 int sz[maxn],vis[maxn];
     31 void getroot(int x,int fa){
     32     sz[x] = 0;
     33     int Max = 0;
     34     for(int i = last[x]; i; i = e[i].last)
     35         if(!vis[e[i].t] && e[i].t != fa){
     36             getroot(e[i].t, x);
     37             sz[x] += sz[e[i].t] + 1;
     38             Max = max(Max, sz[e[i].t] + 1);
     39         }
     40     Max = max(Max,  node - sz[x] - 1);
     41     if(tmax > Max) root = x, tmax = Max;
     42 }
     43 long long ans;
     44 int dep[maxn],path[maxn];
     45 void getpath(int x,int fa,int dis,int bal){
     46     path[bal] = max(path[bal],dis);
     47     for(int i = last[x]; i; i = e[i].last)
     48         if(!vis[e[i].t] && e[i].t != fa) getpath(e[i].t, x, dis + e[i].w, bal + black[e[i].t]);
     49 }
     50 void getdeep(int x,int fa){
     51     dep[x] = black[x];
     52     int Max = 0;
     53     for(int i = last[x]; i; i = e[i].last)
     54         if(!vis[e[i].t] && e[i].t != fa){
     55             getdeep(e[i].t, x);
     56             Max = max(Max, dep[e[i].t]);
     57         }
     58     dep[x] += Max;
     59 }
     60 int prefix[maxn],ch[maxn];
     61 int cmp(int x,int y){
     62     return dep[e[x].t] < dep[e[y].t];
     63 }
     64 void combine(int x){
     65     int size = 0,i,j,la,r,u;
     66     for(i = last[x]; i; i = e[i].last)
     67         if(!vis[e[i].t]){
     68             getdeep(e[i].t, x);
     69             ch[++size] = i;            
     70         }
     71     sort(ch + 1, ch + size + 1, cmp);    
     72     fill(prefix,prefix + dep[e[ch[size]].t] + 1, -inf);
     73     for(i = 1; i <= size; la = u, ++i){
     74         r = ch[i], u = e[r].t;
     75         fill(path, path + dep[u] + 1, -inf);
     76         getpath(u, x, e[r].w, black[u]);
     77         for(j = 0; i != 1 && j <= dep[u] && j <= k - black[x]; ++j){
     78             int pos = min(dep[la], k - j - black[x]);
     79             if(prefix[pos] == -inf) break;
     80             if(path[j] != -inf) ans = max(ans, (long long)path[j] + prefix[pos]);
     81         }
     82         for(j = 0; j <= dep[u]; ++j){
     83             prefix[j] = max(prefix[j], path[j]);
     84             prefix[j] = max(prefix[j], prefix[j-1]);
     85             if(j + black[x] <= k) ans = max(ans, (long long)prefix[j]);
     86         }
     87     }
     88 }
     89 void solve(int x){    
     90     vis[x] = 1;
     91     combine(x);
     92     for(int i = last[x]; i; i = e[i].last)
     93         if(!vis[e[i].t]){
     94             tmax = inf;
     95             node = sz[e[i].t];
     96             getroot(e[i].t, root = 0);
     97             solve(root);
     98         }
     99 }
    100 void work(){
    101     tmax = inf;
    102     node = n;
    103     getroot(1, root = 0);
    104     solve(root);
    105 }
    106 int main()
    107 {
    108     int i;
    109     n = getint(); k = getint(); m = getint();
    110     for(i = 1; i <= m; ++i){
    111         int x = getint();
    112         black[x] = 1;
    113     }
    114     for(i = 1; i < n; ++i){
    115         int a = getint(), b = getint(), w = getint();
    116         add(a,b,w);
    117     }
    118     work();
    119     printf(fmt64,ans);
    120     return 0;
    121 }
    View Code
  • 相关阅读:
    javascript数组查重方法总结
    html5的web存储
    掌握javascript中的最基础数据结构-----数组
    ES解决geoip的location不为geo_point格式
    elk默认分片只有1000导致索引没有创建
    Polysh批量管理服务器
    Git永久删除文件和历史记录
    windows下设置JupyterNotebook默认目录
    windwos安装RabbitMQ
    win7计划任务报该任务映像己损坏或己篡改
  • 原文地址:https://www.cnblogs.com/Mr-ren/p/4204490.html
Copyright © 2020-2023  润新知