【NOIP2017提高A组集训10.28】图
来源:互联网 发布:软件测试工资待遇2017 编辑:程序博客网 时间:2024/05/17 10:28
Description:
有一个n个点A+B条边的无向连通图,有一变量x,每条边的权值都是一个关于x的简单多项式,其中有A条边的权值是k+x,另外B条边的权值是k-x,如果只保留权值形如k+x的边,那么这个图仍是一个连通图,如果只保留权值形如k-x的边,这个图也依然是一个连通图。
给出q组询问,每组询问给出x的值,问此时这个无向连通图的最小生成树权值是多少。
1<=n,q<=100000 , n-1<=A,B<=200000, 0<=k<=10^9 , -10^9<=v<=10^9
题解:
这题考场就差那么一点点就想出来了。
题目都告诉你了A、B两个都可以生成一颗最小生成树。
那一定是对两个都建最小生成树,然后把另外一棵的边从小到大依次插入到这棵中,因为如果是其它边更优,那么这棵最小生成树一定会包含这条边,解释不清,需要感受。
插入到这棵树中,会形成一个环,那么把环上最大的边删掉,如果这条边是k1+x,当前这条是k2-x,那么当v>=(k2-k1)/2,k2-x这条边就会在最优的最小生成树上,答案就可以变小。
所以对所有(k2-k1)/2排个序,读入v二分一下即可算出答案。
加边删边lct维护。
Code:
#include<cstdio>#include<cstring>#include<algorithm>#define ll long long#define min(a, b) ((a) < (b) ? (a) : (b))#define max(a, b) ((a) > (b) ? (a) : (b)) #define fo(i, x, y) for(int i = x; i <= y; i ++)using namespace std;const int N = 3e5 + 50;int z[N], te;int fa[N], t[N][2], pf[N], rev[N], dd[N], mx[N];int lr(int x) {return t[fa[x]][1] == x;}void fan(int x) {if(x) swap(t[x][0], t[x][1]), rev[x] ^= 1;}void down(int x) {if(x && rev[x]) fan(t[x][0]), fan(t[x][1]), rev[x] = 0;}void update(int x) { if(!x) return; mx[x] = x; mx[x] = z[mx[t[x][0]]] > z[mx[x]] ? mx[t[x][0]] : mx[x]; mx[x] = z[mx[t[x][1]]] > z[mx[x]] ? mx[t[x][1]] : mx[x];}void xc(int x) { for(; x; x = fa[x]) dd[++ dd[0]] = x; for(; dd[0]; dd[0] --) down(dd[dd[0]]);}void rotate(int x) { int y = fa[x], k = lr(x); t[y][k] = t[x][!k]; if(t[x][!k]) fa[t[x][!k]] = y; fa[x] = fa[y]; if(fa[y]) t[fa[y]][lr(y)] = x; t[x][!k] = y; fa[y] = x; pf[x] = pf[y]; update(y); update(x);}void splay(int x, int y) { xc(x); while(fa[x] != y) { if(fa[fa[x]] != y) if(lr(x) == lr(fa[x])) rotate(fa[x]); else rotate(x); rotate(x); }}void access(int x) { for(int y = 0; x; update(x), y = x, x = pf[x]) { splay(x, 0); fa[t[x][1]] = 0; pf[t[x][1]] = x; t[x][1] = y; fa[y] = x; pf[y] = 0; } }void makeroot(int x) { access(x); splay(x, 0); fan(x);}void link(int x, int y) { makeroot(x); pf[x] = y; access(x);}void cut(int x, int y) { makeroot(x); access(y); splay(y, 0); t[y][0] = fa[x] = pf[x] = 0; update(y);}int n, A, B, q;struct edge { int u, v, k;}a[N * 2], b[N * 2];bool rank(edge a, edge b) { return a.k < b.k;}int f[N];int find(int x) { return f[x] == x ? x : (f[x] = find(f[x]));}void BT(edge *a, int A) { sort(a + 1, a + A + 1, rank); fo(i, 1, n) f[i] = i; int tot = 0; fo(i, 1, A) { int x = a[i].u, y = a[i].v, k = a[i].k; if(find(x) != find(y)) { f[f[x]] = f[y]; a[++ tot] = a[i]; } if(tot == n - 1) break; }}struct node { int x; ll y;} d[N];bool rank_d(node a, node b) {return a.x < b.x;}int main() { freopen("graph.in", "r", stdin); freopen("graph.out", "w", stdout); scanf("%d %d %d %d", &n, &A, &B, &q); fo(i, 1, A) scanf("%d %d %d", &a[i].u, &a[i].v, &a[i].k); fo(i, 1, B) scanf("%d %d %d", &b[i].u, &b[i].v, &b[i].k); BT(a, A); BT(b, B); fo(i, 0, n) z[i] = -2e9; ll sumk = 0; int te = n; fo(i, 1, n - 1) { int x = a[i].u, y = a[i].v, k = a[i].k; sumk += k; te ++; z[te] = k; link(x, te); link(y, te); } int d0 = 0; fo(i, 1, n - 1) { int x = b[i].u, y = b[i].v, k = b[i].k; makeroot(x); access(y); splay(y, 0); int mb = mx[y]; if(mb > n + n - 1 || mb <= n) continue; int x1 = a[mb - n].u, y1 = a[mb - n].v, k1 = a[mb - n].k; cut(x1, mb); cut(y1, mb); te ++; z[te] = -2e9; link(x, te); link(y, te); d[++ d0].x = (k - k1 + 1) / 2; d[d0].y = k - k1; } sort(d + 1, d + d0 + 1, rank_d); fo(i, 2, d0) d[i].y += d[i - 1].y; fo(ii, 1, q) { int u; scanf("%d", &u); int ans = 0; for(int l = 1, r = d0; l <= r; ) { int m = l + r >> 1; if(d[m].x <= u) ans = m, l = m + 1; else r = m - 1; } printf("%lld\n", sumk + d[ans].y + (ll)(n - 1 - ans * 2) * u); }}
阅读全文
1 0
- 【NOIP2017提高A组集训10.28】图
- 【NOIP2017提高A组集训10.28】图
- 【JZOJ 5433】【NOIP2017提高A组集训10.28】图
- 【JZOJ5433】【NOIP2017提高A组集训10.28】图
- jzoj5433 【NOIP2017提高A组集训10.28】图
- jzoj【NOIP2017提高A组集训10.28】图
- JZOJ 5432. 【NOIP2017提高A组集训10.28】三元组
- 【JZOJ 5432】【NOIP2017提高A组集训10.28】三元组
- jzoj5432【NOIP2017提高A组集训10.28】三元组
- 【JZOJ5432】【NOIP2017提高A组集训10.28】三元组
- 【NOIP2017提高A组集训10.28】三元组
- JZOJ5432. 【NOIP2017提高A组集训10.28】三元组
- 【NOIP2017提高A组集训10.28】三元组
- 【JZOJ 5431】【NOIP2017提高A组集训10.28】序列操作
- 【JZOJ5431】【NOIP2017提高A组集训10.28】序列操作
- JZOJ 5431. 【NOIP2017提高A组集训10.28】序列操作
- JZOJ5431. 【NOIP2017提高A组集训10.28】序列操作
- 【NOIP2017提高A组集训10.28】序列操作
- Leetcode 6. ZigZag Conversion(java版)
- Linux网络编程--(2)网络编程基础
- a regression model that predicts one model variable.
- C++队列模拟银行排队叫号(加州大学伯克利分校计算机专业数据结构与算法作业)
- python 斐波那契数列
- 【NOIP2017提高A组集训10.28】图
- 西安现场打铁记
- 拉格朗日乘子法(Lagrange Multiplier)详解以及乘子lambda的意义
- Kubernetes集群部署(redhat7.2)
- Django模型
- rpm,yum,软件安装,yum源的配置
- SQL数据库select基本使用
- 获取主机名称和ip,用户名
- Python学习零散杂记(2017-10-30)