JZOJ6232 【NOI2019模擬2019.6.25】喜歡最最痛(凸函數,貪心,動態dp)

Description:


神樹大人種了一棵有邊權的樹,由於這是神樹大人種的樹,所以這棵樹被命名爲神
神樹。神神樹的邊權爲正. 整. 數. 。神樹大人命令龔詩鋒從 1 號點開始走一個路徑並最終
回到1 號點,且這條路徑經過了所有的邊。一條路徑的代價就是它經過的邊的邊權之
和。龔詩鋒可以加若干條額外邊,第 i 條加的額外邊的邊權爲正. 整. 數. Ai。注. 意. ,龔. 詩. 鋒.
不. 一. 定. 要. 經. 過. 所. 有. 的. 額. 外. 邊. 。
由於龔詩鋒喜歡最最痛,所以對於所有的K ∈[0;m],你需要輸出允許加<= K 條額
外邊的最小路徑代價。
1<=n<=1e5,5s

題解:


不難想到假設求出了f[i]f[i]表示ii條不相交路徑的最大長度和,那麼對一個K,就需要求出l,使2f[i]+Kl2*邊權和-f[i]+前K條邊中前l小的和的最小值

當然這個可以暴力用個平衡樹(離線線段樹)二分。

注意到ff是個凸函數,然後前l小的和也是個凸函數,且隨着K的增大,l只會右移,所以可以用兩個multiset維護,一個存選了的l條邊,另一個存沒選的,細節比較簡單不講了。

那麼問題在於求f,可以暴力對拍,複雜度O(n2)O(n^2)

然後這個東西是優化不了的,考慮一個貪心,每次選直徑,把直徑邊權取反,繼續找直徑。

顯然我是不會證明這個東西的正確性的,但是至少能找到i條不相交的路徑。

那麼這個東西顯然可以用ddp優化,update細節有點多,還需要用一個multiset維護一個點的虛兒子的最小和次小,access要改改寫法。

重載一堆東西以後還是可以寫的hhh

複雜度O(n log2n)O(n~log^2n),常數巨大

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i <  B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

int by;

const int N = 2e5 + 5;

int n, m, x, y, z, w[N];
int v[N];

struct P {
	int x, y; ll z;
	P(){}
	P(int _x, int _y, ll _z) { x = _x, y = _y, z = _z;}
};
bool operator <(P a, P b) {
	if(a.z < b.z) return 1;
	if(a.z > b.z) return 0;
	if(a.x < b.x) return 1;
	if(a.x > b.x) return 0;
	return a.y < b.y;
}
P operator +(P a, P b) { return P(!a.x ? b.x : a.x, !b.y ? a.y : b.y, a.z + b.z);}

P fan(P a) { swap(a.x, a.y); return a;}

struct nod {
	P f1, f2, g, v;
};

nod a[N][2][2];
multiset<P> s[N], g[N];
int fa[N], t[N][2], rev[N], rf[N], dd[N], pf[N];
#define i0 t[i][0]
#define i1 t[i][1]

P calc1(multiset<P> &s) {
	if(!s.size()) return P(0, 0, 0);
	return *s.rbegin();
}
P calc2(multiset<P> &s) {
	if(s.size() < 2) return P(0, 0, 0);
	return (*++s.rbegin());
}
template<class T> void cmax(T &a, T b) {if(a < b) a = b;} 
void upd(int i, multiset<P> &s, multiset<P> &g, int V, nod &a, nod b, nod c) {
	P w = P(i, i, V);
	a.f1 = b.f1; cmax(a.f1, b.v + w + c.f1); cmax(a.f1, b.v + w + calc1(s));
	a.f2 = c.f2; cmax(a.f2, b.f2 + w + c.v); cmax(a.f2, fan(calc1(s)) + w + c.v);
	a.g = max(b.g, c.g);
	if(g.size()) cmax(a.g, *g.rbegin());
	cmax(a.g, b.f2 + w + c.f1);
	cmax(a.g, fan(calc1(s)) + w + calc2(s));
	cmax(a.g, b.f2 + w + calc1(s));
	cmax(a.g, fan(calc1(s)) + w + c.f1);
	a.v = b.v + w + c.v;
}
void upd(int i) {
	upd(i, s[i], g[i], v[i], a[i][0][0], a[i0][0][0], a[i1][0][0]);
	upd(i, s[i], g[i], v[i], a[i][1][0], a[i1][1][0], a[i0][1][0]);
	upd(i, s[i], g[i], -v[i], a[i][0][1], a[i0][0][1], a[i1][0][1]);
	upd(i, s[i], g[i], -v[i], a[i][1][1], a[i1][1][1], a[i0][1][1]);
}
void fan(int i) {
	if(i) {
		swap(i0, i1);
		swap(a[i][0][0], a[i][1][0]);
		swap(a[i][0][1], a[i][1][1]);
		rev[i] ^= 1;
	}
}
void fu(int i) {
	if(i) {
		v[i] = -v[i];
		swap(a[i][0][0], a[i][0][1]);
		swap(a[i][1][0], a[i][1][1]);
		rf[i] ^= 1;
	}
}
void down(int i) {
	if(rev[i]) fan(i0), fan(i1), rev[i] = 0;
	if(rf[i]) fu(i0), fu(i1), rf[i] = 0;
}
void xc(int x) {
	for(; x; x = fa[x]) dd[++ dd[0]] = x;
	while(dd[0]) down(dd[dd[0] --]);
}
int lr(int x) { return t[fa[x]][1] == x;}
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;
	fa[y] = x; t[x][!k] = y; pf[x] = pf[y];
	upd(y); upd(x);
}
void splay(int x, int y) {
	xc(x);
	for(; fa[x] != y; rotate(x))
		if(fa[fa[x]] != y) rotate(lr(x) == lr(fa[x]) ? fa[x] : x);
}
void access(int x) {
	int xx = x;
	for(int y = 0; x; ) {
		splay(x, 0);
		if(y) {
			s[x].erase(s[x].find(a[y][0][0].f1));
			g[x].erase(g[x].find(a[y][0][0].g));
		}
		y = x, x = pf[x];
	}
	x = xx;
	for(int y = 0; x; ) {
		splay(x, 0); fa[t[x][1]] = 0, pf[t[x][1]] = x;
		if(t[x][1]) {
			s[x].insert(a[t[x][1]][0][0].f1);
			g[x].insert(a[t[x][1]][0][0].g);
		}
		t[x][1] = y, fa[y] = x, pf[y] = 0;
		y = x, upd(x), x = pf[x];
	}
}
void mr(int x) {
	access(x); splay(x, 0);
	fan(x);
}
void link(int x, int y) {
	mr(x); mr(y);
	pf[x] = y;
	s[y].insert(a[x][0][0].f1);
	g[y].insert(a[x][0][0].g);
	access(x);
}

ll f[N];

ll sum, ans;
multiset<int> s1, s2;

int main() {
	freopen("love.in", "r", stdin);
	freopen("love.out", "w", stdout);
	scanf("%d %d", &n, &m);
	fo(i, 1, n - 1) {
		scanf("%d %d %d", &x, &y, &z);
		ans += z * 2;
		v[n + i] = z;
		link(x, n + i); link(n + i, y);
	}
	fo(i, 1, n) {
		mr(1);
		P p = a[1][0][0].g;
		f[i] = f[i - 1];
		if(p.z >= 0) {
			f[i] += p.z;
			mr(p.x); access(p.y); splay(p.y, 0);
			fu(p.y);
		}
	}
	pp("%lld ", ans);
	int l = 0;
	fo(i, 1, m) {
		scanf("%d", &w[i]);
		if(s1.size() && (*s1.rbegin()) > w[i]) {
			sum += w[i] - (*s1.rbegin());
			s2.insert(*s1.rbegin());
			s1.erase(s1.find(*s1.rbegin()));
			s1.insert(w[i]);
		} else s2.insert(w[i]);
		while(s2.size() && (sum + *s2.begin()) - f[l + 1] <= sum - f[l]) {
			sum += *s2.begin();
			s1.insert(*s2.begin());
			s2.erase(s2.begin());
			l ++;
		}
		pp("%lld ", ans + sum - f[l]);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章