zoukankan      html  css  js  c++  java
  • BZOJ4860 BJOI2017 树的难题 点分治、线段树合并

    传送门


    只会线段树……关于单调队列的解法可以去看“重建计划”一题。

    看到路径长度$in [L,R]$考虑点分治。可以知道,在当前分治中心向其他点的路径中,始边(也就是分治中心到对应子树的根的那一条边)颜色相同的两条路径在拼合的时候在加上两条路径的权值之后需要减掉始边颜色的权值(因为被计算了两次),而初始边颜色不同的进行拼合就直接将两条路径的权值加起来即可。我们考虑分开维护这两种拼合。

    在每一个分治中心里,我们对其引出的边按照颜色排序(目的是使得始边颜色相同的若干子树放在一起统一遍历),维护两个线段树,一个维护之前遍历过的子树中初始边颜色与当前子树不同的子树中每种长度的路径的最大权值,另一个维护之前遍历过的子树中初始边颜色与当前子树相同的子树中每种长度的路径的最大权值。

    那么我们每一次遍历完一棵子树,在线段树中对于每一种长度的路径在线段树上查询可以拼合的长度的路径的最大权值,记得在第二个线段树中询问到的答案需要减去始边颜色的权值,然后用这一棵子树的路径更新第二个线段树。每一次遍历完一种颜色就把第二个线段树合并到第一个线段树内即可。复杂度$O(nlog^2n)$

      1 #include<bits/stdc++.h>
      2 #define INF 0x7fffffff
      3 #define int long long
      4 #define mid ((l + r) >> 1)
      5 //This code is written by Itst
      6 using namespace std;
      7 
      8 inline int read(){
      9     int a = 0;
     10     bool f = 0;
     11     char c = getchar();
     12     while(c != EOF && !isdigit(c)){
     13         if(c == '-')
     14             f = 1;
     15         c = getchar();
     16     }
     17     while(c != EOF && isdigit(c)){
     18         a = (a << 3) + (a << 1) + (c ^ '0');
     19         c = getchar();
     20     }
     21     return f ? -a : a;
     22 }
     23 
     24 const int MAXN = 200010;
     25 vector < pair < int , int > > Edge[MAXN];
     26 struct node{
     27     int l , r , maxN;
     28 }Tree[MAXN * 30];
     29 int N , M , L , R , ans , cntNode , nowSize , minSize , minInd , roota , rootb;
     30 int val[MAXN] , size[MAXN] , sz[MAXN] , mx[MAXN];
     31 bool vis[MAXN];
     32 
     33 inline int allocate(){
     34     int t = ++cntNode;
     35     Tree[t].l = Tree[t].r = 0;
     36     Tree[t].maxN = -INF;
     37     return t;
     38 }
     39 
     40 inline void pushup(int x){
     41     Tree[x].maxN = max(Tree[Tree[x].l].maxN , Tree[Tree[x].r].maxN);
     42 }
     43 
     44 inline int max(int a , int b){
     45     return a > b ? a : b;
     46 }
     47 
     48 int merge(int p , int q){
     49     if(!p)
     50         return q;
     51     if(!q)
     52         return p;
     53     Tree[p].maxN = max(Tree[p].maxN , Tree[q].maxN);
     54     Tree[p].l = merge(Tree[p].l , Tree[q].l);
     55     Tree[p].r = merge(Tree[p].r , Tree[q].r);
     56     return p;
     57 }
     58 
     59 void insert(int& now , int l , int r , int tar , int num){
     60     if(!now)
     61         now = allocate();
     62     if(l == r)
     63         Tree[now].maxN = max(Tree[now].maxN , num);
     64     else{
     65         if(mid >= tar)
     66             insert(Tree[now].l , l , mid , tar , num);
     67         else
     68             insert(Tree[now].r , mid + 1 , r , tar , num);
     69         pushup(now);
     70     }
     71 }
     72 
     73 int query(int now , int l , int r , int L , int R){
     74     if(l >= L && r <= R)
     75         return Tree[now].maxN;
     76     if(!now)
     77         return -INF;
     78     int maxN = -INF;
     79     if(mid >= L)
     80         maxN = max(maxN , query(Tree[now].l , l , mid , L , R));
     81     if(mid < R)
     82         maxN = max(maxN , query(Tree[now].r , mid + 1 , r , L , R));
     83     return maxN;
     84 }
     85 
     86 void getSize(int x){
     87     vis[x] = 1;
     88     ++nowSize;
     89     for(int i = 0 ; i < sz[x] ; ++i){
     90         int t = Edge[x][i].second;
     91         if(!vis[t])
     92             getSize(t);
     93     }
     94     vis[x] = 0;
     95 }
     96 
     97 void getRoot(int x){
     98     size[x] = vis[x] = 1;
     99     int maxN = 0;
    100     for(int i = 0 ; i < sz[x] ; ++i){
    101         int t = Edge[x][i].second;
    102         if(!vis[t]){
    103             getRoot(t);
    104             size[x] += size[t];
    105             maxN = max(maxN , size[t]);
    106         }
    107     }
    108     maxN = max(maxN , nowSize - size[x]);
    109     if(maxN < minSize){
    110         minSize = maxN;
    111         minInd = x;
    112     }
    113     vis[x] = 0;
    114 }
    115 
    116 void dfs(int x , int c , int len , int nowCol){
    117     if(len > R)
    118         return;
    119     vis[x] = 1;
    120     mx[len] = max(mx[len] , c);
    121     for(int i = 0 ; i < sz[x] ; ++i){
    122         int t = Edge[x][i].second;
    123         if(!vis[t])
    124             dfs(Edge[x][i].second , nowCol == Edge[x][i].first ? c : c + val[Edge[x][i].first] , len + 1 , Edge[x][i].first);
    125     }
    126     vis[x] = 0;
    127 }
    128 
    129 void solve(int x){
    130     nowSize = cntNode = roota = rootb = 0;
    131     minSize = INF;
    132     getSize(x);
    133     getRoot(x);
    134     int root = minInd;
    135     getSize(root);
    136     vis[root] = 1;
    137     for(int i = 0 ; i < sz[root] ; ++i){
    138         int t = Edge[root][i].second , r = Edge[root][i].first;
    139         if(!vis[t]){
    140             memset(mx , -0x3f , sizeof(int) * (size[t] + 1));
    141             if(rootb && r != Edge[root][i - 1].first){
    142                 roota = merge(roota , rootb);
    143                 rootb = 0;
    144             }
    145             dfs(t , val[r] , 1 , r);
    146             for(int i = 1 ; i <= size[t] && i < R && mx[i] != mx[0] ; ++i)
    147                 ans = max(max(ans , i >= L && i <= R ? mx[i] : -INF) , max(query(roota , 1 , R , max(1 , L - i) , R - i) , query(rootb , 1 , R , max(1 , L - i) , R - i) - val[r]) + mx[i]);
    148             ans = max(ans , mx[R]);
    149             for(int i = 1 ; i <= size[t] && i < R && mx[i] != mx[0] ; ++i)
    150                 insert(rootb , 1 , R , i , mx[i]);
    151         }
    152     }
    153     for(int i = 0 ; i < sz[root] ; ++i){
    154         int t = Edge[root][i].second;
    155         if(!vis[t])
    156             solve(t);
    157     }
    158 }
    159 
    160 signed main(){
    161 #ifndef ONLINE_JUDGE
    162     freopen("3714.in" , "r" , stdin);
    163     //freopen("3714.out" , "w" , stdout);
    164 #endif
    165     Tree[0].maxN = ans = -INF;
    166     N = read();
    167     M = read();
    168     L = read();
    169     R = read();
    170     for(int i = 1 ; i <= M ; ++i)
    171         val[i] = read();
    172     for(int i = 1 ; i < N ; ++i){
    173         int a = read() , b = read() , c = read();
    174         Edge[a].push_back(make_pair(c , b));
    175         Edge[b].push_back(make_pair(c , a));
    176         ++sz[a];
    177         ++sz[b];
    178     }
    179     for(int i = 1 ; i <= N ; ++i)
    180         sort(Edge[i].begin() , Edge[i].end());
    181     solve(1);
    182     cout << ans;
    183     return 0;
    184 }
  • 相关阅读:
    org.tinygroup.tinydb-数据库开发组件
    org.tinygroup.database-数据库元数据定义
    org.tinygroup.databasebuinstaller-数据库结构及元数据自动创建
    org.tinygroup.dbrouter-数据库分区分表
    org.tinygroup.metadata-元数据定义
    org.tinygroup.jsqlparser-SQL解析器
    org.tinygroup.xmlparser-XML解析器
    四则运算程序扩展:将程序改为java语言,并允许用户输入,对输入结果进行验证
    课堂练习四: 返回一个整数数组中最大子数组的和。
    自动生成四则运算问题的测试
  • 原文地址:https://www.cnblogs.com/Itst/p/10074845.html
Copyright © 2011-2022 走看看