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 }