[树链剖分]hihocoder1883
描述
有一个无向图,有n个点,m1条第一类边和m2条第二类边。第一类边有边权,第二类边无边权。请为第二类的每条边定义一个边权,使得第二类边可能全部出现在该无向图的最小生成树上,同时要求第二类边的边权总和尽可能大。
注:第二类边不会形成环
输入
第一行三个数n,m2,m1
接下来m2行,每行两个数,描述一条第二类边,分别表示两个端点接下来m1行,每行三个数,描述一条第一类边,分别表示两个端点和边权
对于30%的数据,n ≤ 5
对于60%的数据,n ≤ 1000
对于100%的数据,1 ≤ n ≤ 100000, m1 ≤ 2 × n, m2 < n
输出
输出一个数,表示第二类边的权值总和最大可能为多少。(若可能为无穷大则输出-1)
- 样例输入
-
5 2 3 1 2 4 5 2 3 100 3 4 100 1 5 1000
- 样例输出
-
2000
题解:
将所有第二类边权当作0处理,先构造出生成树。
之后对于不在生成树上的边e,我们尝试加入e,如果构成的环中有一条边大于e则将那条边用e代替更优。
所以我们构造出生成树后,令第二类边权值为x = inf,每次对于一条不在生成树中的边权值w,让环上的第二类边权值x = min(x, w),即树上的链赋值操作,树链剖分即可。
1 #include <bits/stdc++.h> 2 3 #define ll long long 4 #define ull unsigned long long 5 #define st first 6 #define nd second 7 #define pii pair<int, int> 8 #define pil pair<int, ll> 9 #define pli pair<ll, int> 10 #define pll pair<ll, ll> 11 #define tiii tuple<int, int, int> 12 #define pw(x) ((1LL)<<(x)) 13 #define lson l, m, rt<<1 14 #define rson m+1, r, rt<<1|1 15 #define sqr(x) ((x)*(x)) 16 #define SIZE(A) ((int)(A.size())) 17 #define LENGTH(A) ((int)(A.length())) 18 #define FIN freopen("A.in","r",stdin); 19 #define FOUT freopen("A.out","w",stdout); 20 using namespace std; 21 /***********/ 22 23 template<typename T> 24 bool scan (T &ret) { 25 char c; 26 int sgn; 27 if (c = getchar(), c == EOF) return 0; //EOF 28 while (c != '-' && (c < '0' || c > '9') ) c = getchar(); 29 sgn = (c == '-') ? -1 : 1; 30 ret = (c == '-') ? 0 : (c - '0'); 31 while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0'); 32 ret *= sgn; 33 return 1; 34 } 35 template<typename N,typename PN>inline N flo(N a,PN b){return a>=0?a/b:-((-a-1)/b)-1;} 36 template<typename N,typename PN>inline N cei(N a,PN b){return a>0?(a-1)/b+1:-(-a/b);} 37 template<typename T>inline int sgn(T a) {return a>0?1:(a<0?-1:0);} 38 template<class T> int countbit(const T &n) { return (n==0)?0:(1+countbit(n&(n-1))); } 39 template <class T1, class T2> 40 bool gmax(T1 &a, const T2 &b) { return a < b? a = b, 1:0;} 41 template <class T1, class T2> 42 bool gmin(T1 &a, const T2 &b) { return a > b? a = b, 1:0;} 43 template <class T> inline T lowbit(T x) {return x&(-x);} 44 45 template<class T1, class T2> 46 ostream& operator <<(ostream &out, pair<T1, T2> p) { 47 return out << "(" << p.st << ", " << p.nd << ")"; 48 } 49 template<class A, class B, class C> 50 ostream& operator <<(ostream &out, tuple<A, B, C> t) { 51 return out << "(" << get<0>(t) << ", " << get<1>(t) << ", " << get<2>(t) << ")"; 52 } 53 template<class T> 54 ostream& operator <<(ostream &out, vector<T> vec) { 55 out << "("; for(auto &x: vec) out << x << ", "; return out << ")"; 56 } 57 void testTle(int &a){ 58 while(1) a = a*(ll)a%1000000007; 59 } 60 const ll inf = 0x3f3f3f3f; 61 const ll INF = 1e17; 62 const int mod = 1e9+7; 63 const double eps = 1e-5; 64 const int N = 100000+10; 65 const double pi = acos(-1.0); 66 67 /***********/ 68 69 70 struct Edge{ 71 int x, y, w; 72 }; 73 Edge edge1[N+N], edge2[N]; 74 vector<pii> ve[N]; 75 76 int n, m1, m2; 77 int fa[N]; 78 int findf(int x) { return x == fa[x]? x: fa[x] = findf(fa[x]);} 79 80 int dfn, f[N], fdis[N], d[N], size[N], son[N], top[N], st[N], en[N]; 81 struct Node { 82 int maxval; 83 int tag; 84 }; 85 Node T[N<<2]; 86 int a[N]; 87 88 void pushup(int rt) { 89 T[rt].maxval = max(T[rt<<1].maxval, T[rt<<1|1].maxval); 90 } 91 void pushdown(int rt) {//区间赋的值递增,之后赋的值必大于之前赋的值,故已有赋值则可跳过 92 if(T[rt].tag) { 93 if(!T[rt<<1].tag&&T[rt<<1].maxval > T[rt].tag) 94 T[rt<<1].tag = T[rt].tag; 95 if(!T[rt<<1|1].tag&&T[rt<<1|1].maxval > T[rt].tag) 96 T[rt<<1|1].tag = T[rt].tag; 97 T[rt].tag = 0; 98 } 99 if(T[rt].tag) { 100 if(!T[rt<<1].tag&&T[rt<<1].maxval > T[rt].tag) 101 T[rt<<1].tag = T[rt].tag; 102 if(!T[rt<<1|1].tag&&T[rt<<1|1].maxval > T[rt].tag) 103 T[rt<<1|1].tag = T[rt].tag; 104 T[rt].tag = 0; 105 } 106 } 107 void build(int l, int r, int rt) { 108 if(l == r) { 109 T[rt] = {a[l], 0}; 110 return ; 111 } 112 int m = (l+r) >> 1; 113 build(lson); 114 build(rson); 115 pushup(rt); 116 } 117 void update(int L, int R, int val, int l, int r, int rt) { 118 if(L <= l&&r <= R) { 119 if(T[rt].tag == 0||T[rt].tag > val) T[rt].tag = val; 120 return ; 121 } 122 pushdown(rt); 123 int m = (l+r) >> 1; 124 if(L <= m) update(L, R, val, lson); 125 if(R > m) update(L, R, val, rson); 126 } 127 128 void dfs(int x){ 129 size[x] = 1; 130 for(pii e: ve[x]) { 131 int y = e.st; 132 if(y != f[x]){ 133 f[y] = x, d[y] = d[x]+1; 134 fdis[y] = e.nd; 135 dfs(y), size[x] += size[y]; 136 if(size[y] > size[son[x]]) 137 son[x] = y; 138 } 139 } 140 } 141 void dfs2(int x, int y){ 142 st[x] = ++dfn; top[x] = y; a[dfn] = fdis[x]; 143 if(son[x]) dfs2(son[x], y); 144 for(pii e: ve[x]) { 145 int y = e.st; 146 if(y != son[x]&&y != f[x]) 147 dfs2(y, y); 148 } 149 en[x]=dfn; 150 } 151 //查询x,y两点的lca 152 int lca(int x,int y){ 153 for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]]) swap(x, y); 154 return d[x]<d[y]?x:y; 155 } 156 //x是y的祖先,查询x到y方向的第一个点 157 int lca2(int x, int y){ 158 int t; 159 while(top[x]!=top[y])t=top[y],y=f[top[y]]; 160 return x==y?t:son[x]; 161 } 162 //对x到y路径上的点进行操作 163 void chain(int x, int y, int val){ 164 for(;top[x]!=top[y];x=f[top[x]]){ 165 if(d[top[x]]<d[top[y]]) swap(x, y); 166 //change(st[top[x]],st[x]); 167 update(st[top[x]], st[x], val, 1, n, 1); 168 } 169 if(d[x]<d[y]) swap(x, y); 170 //change(st[y],st[x]); 171 update(st[y], st[x], val, 1, n, 1); 172 } 173 174 long long ans; 175 bool solve(int l, int r, int rt) { 176 if(T[rt].maxval != inf) return true; 177 if(l == r) { 178 if(T[rt].tag == 0) return false; 179 ans += T[rt].tag; 180 return true; 181 } 182 pushdown(rt); 183 int m = (l+r) >> 1; 184 return solve(lson) && solve(rson); 185 } 186 int main() { 187 scanf("%d%d%d", &n, &m2, &m1); 188 for(int i = 0, x, y; i < m2; i++) { 189 scanf("%d%d", &x, &y); 190 edge2[i] = {x, y, 0}; 191 } 192 for(int i = 0, x, y, w; i < m1; i++) { 193 scanf("%d%d%d", &x, &y, &w); 194 edge1[i] = {x, y, w}; 195 } 196 197 sort(edge1, edge1+m1, [](Edge e1, Edge e2) { return e1.w < e2.w; }); 198 for(int i = 1; i <= n; i++) fa[i] = i; 199 for(int i = 0; i < m2; i++) { 200 Edge e = edge2[i]; 201 int fx = findf(e.x), fy = findf(e.y); 202 if(fx != fy) { 203 fa[fx] = fy; 204 ve[e.x].push_back({e.y, inf}); 205 ve[e.y].push_back({e.x, inf}); 206 } 207 } 208 vector<Edge> tmp; 209 for(int i = 0; i < m1; i++) { 210 Edge e = edge1[i]; 211 int fx = findf(e.x), fy = findf(e.y); 212 if(fx != fy) { 213 fa[fx] = fy; 214 ve[e.x].push_back({e.y, e.w}); 215 ve[e.y].push_back({e.x, e.w}); 216 } 217 else tmp.push_back(e);//将e.x -> e.y路径上的边w = min(w, e.w); 218 } 219 220 dfs(1); 221 dfs2(1, 1); 222 build(1, n, 1); 223 for(Edge e: tmp) { 224 int x = e.x, y = e.y, w = e.w; 225 int ancestor = lca(x, y); 226 if(ancestor != x) { 227 int xx = lca2(ancestor, x); 228 chain(xx, x, w); 229 } 230 if(ancestor != y) { 231 int yy = lca2(ancestor, y); 232 chain(yy, y, w); 233 } 234 } 235 printf("%lld\n", solve(1, n, 1)? ans: -1); 236 return 0; 237 }
诸神对凡人心生艳羡,厌倦天堂。