1. 程式人生 > >Luogu3714/BZOJ4860 BJOI2017 樹的難題 點分治、線段樹

Luogu3714/BZOJ4860 BJOI2017 樹的難題 點分治、線段樹

傳送門——Luogu

傳送門——BZOJ


只會線段樹……關於單調佇列的解法可以去看“重建計劃”一題。

看到路徑長度$\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 }