<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      P11673 [USACO25JAN] Median Heap G 題解

      題目傳送門(mén)

      洛谷P11673

      題目大意

      對(duì)于一顆完全二叉樹(shù),定義其節(jié)點(diǎn) \(u\)

      • 左兒子 \(ls=u\times2\),右兒子 \(rs=u\times2+1\)
      • 父親為 \(\lfloor \frac u2\rfloor\)
      • 置換操作:將 \(u\) 的值換為 \(\{u,\) \(ls\)(如果有), \(rs\)(如果有)\(\}\) 的中位數(shù),代價(jià)為 \(\text0\)
      • 修改操作:將 \(u\) 的值修改為任意數(shù),代價(jià)為 \(c_u\)
      • “近似中位數(shù)”:從最后一個(gè)節(jié)點(diǎn) \(n\) 開(kāi)始向前執(zhí)行,若此節(jié)點(diǎn)非葉子節(jié)點(diǎn),則進(jìn)行置換操作,最后節(jié)點(diǎn) \(1\) (根)的值即為近似中位數(shù)

      現(xiàn)在給你這顆樹(shù)的初始權(quán)值,和修改每個(gè)點(diǎn)的代價(jià)。
      再給出一個(gè)詢問(wèn)列表 \(m_1,m_2,\cdots,m_q\),對(duì)于每個(gè)詢問(wèn),回答使樹(shù)的近似中位數(shù)為 \(m_i\) 所需要的最小代價(jià)。

      部分分

      首先我們來(lái)看 \(n,q\leq1000\) 的部分。
      定義函數(shù)

      \[p(m_i,a_u)=\begin{cases}0&m_i<a_u\\1&m_i=a_u\\2&m_i>a_u\end{cases} \\并維護(hù)每個(gè)詢問(wèn)都刷新的數(shù)組\ f_u=p(m_i,a_u),此處\ m_i 為全局變量 \]

      定義dp數(shù)組

      \[dp[u][\text{case}]=修改節(jié)點(diǎn)\ u\ 使其\ 近似中位數(shù)\begin{cases}\text{case}=0&<\ m_i\\\text{case}=1&=\ m_i\\\text{case}=2&>\ m_i\end{cases}的最小代價(jià) \]

      轉(zhuǎn)移方程

      \[dp[u][s]=\min_{\text{med}\{i,j,k\}=s}{dp[ls][i]+dp[rs][j]+\text{cost}[k]} \]

      其中 \(\text{cost}(k)\) 代表將 \(a_u\) 修改為 小于/等于/大于 \(m_i\) 的代價(jià)
      具體地,

      vector<int> cost = {c[u], c[u], c[u]};
      cost[f[u]] = 0;
      

      dp代碼實(shí)現(xiàn):

      #include <bits/stdc++.h>
      using namespace std;
      #define int long long
      #define med(a, b, c) (a ^ b ^ c ^ min({a, b, c}) ^ max({a, b, c}))
      #define p(m, x) (x < m ? 0 : x == m ? 1 : 2)
      #define ls u << 1
      #define rs u << 1 | 1
      const int N = 2e5 + 5, M = 4e5 + 5;
      const int INF = 1e18;
      int n, q;
      vector<int> a(N), c(N);
      vector<int> ans(M);
      vector<int> f(N); // f[i]=p(m,i)
      int dp[M][3];
      // 更新使節(jié)點(diǎn)u的近似中位數(shù)為m的最小代價(jià)
      void update(int u)
      {
      	// 將 a[u] 修改為一個(gè)  <m    =m    >m   的數(shù)的代價(jià)
      	vector<int> cost = {c[u], c[u], c[u]};
      	cost[f[u]] = 0;
      
      	if (rs >= n) { // 葉子結(jié)點(diǎn)
      		for (int i = 1; i <= 3; ++i) dp[u][i] = cost[i];
      		return ;
      	}
      
      	dp[u][0] = dp[u][1] = dp[u][2] = INF;
      	for (int i = 0; i < 3; ++i) {
      		for (int j = 0; j < 3; ++j) {
      			for (int k = 0; k < 3; ++k) {
      				int mod = med(i, j, k);
      				dp[u][mod] = min(dp[u][mod], dp[ls][i] + dp[rs][j] + cost[k]);
      			}
      		}
      	}
      }
      

      對(duì)于每個(gè)詢問(wèn),我們都

      for (int i = 1; i <= q; ++i) {
      	int m;
      	cin >> m;
      	for (int j = n; j; --j) {
      		f[j] = p(m, a[j]);
      		update(j);
      	}
      	cout << dp[1][1] << '\n';
      }
      

      注意這里查看 f[j] 的修改情況時(shí)一定要倒序!!!這樣才能保證從葉子節(jié)點(diǎn)開(kāi)始修改,否則你先把父親更新了結(jié)果兒子還沒(méi)更等于沒(méi)更,包WA的。

      部分分優(yōu)化(滿分)

      我們注意到,可以把問(wèn)詢離線下來(lái)。
      把問(wèn)詢從小到大排序后,我們?cè)倏瓷洗a,可以發(fā)現(xiàn)每次增大詢問(wèn)值后,并不是所有的 \(f[j]\) 都需要修改。
      又因?yàn)橹挥?\(f[j]\) 修改才會(huì)造成 dp 改變,只需要每輪查看哪些 \(f[j]\) 被修改了,針對(duì)它們更新從這個(gè)節(jié)點(diǎn)j不斷往上更新父親的 dp,因?yàn)轱@然除了父親這個(gè)節(jié)點(diǎn)無(wú)法更改任何其他 dp。

      顯然 f[j] 是越修越大的,因此最多修改2次(0->1,1->2)。

      那么,現(xiàn)在我們只需尋找一種高效的方式,每次精準(zhǔn)查找需要修改的 \(f[j]\),顯然不能遍歷,否則直接給你炸成 Time Limit Enough
      這個(gè)時(shí)候,我們想到,可以開(kāi)一個(gè) \(pos[val]\),記錄值為 \(a_u=val\) 的 下標(biāo) \(u\),每次問(wèn)詢值為 \(m\) 時(shí),就遍歷 \(pos[m]\),將其中所有 \(f[j]\) 修改為 \(1\),注意一定要將 \(pos[m]\) 逆序,使其中內(nèi)容從 單調(diào)遞增變?yōu)?strong>單調(diào)遞減.然后更新dp。更完后,下一個(gè) \(m\) 肯定比現(xiàn)在大,因此我們可以預(yù)測(cè)這些點(diǎn)下一輪的 \(f[j]\) 必定為 \(2\) ,所以可以在現(xiàn)在這個(gè)循環(huán)提前修改。
      代碼實(shí)現(xiàn):

      void modify(int u, int state) // 要修的 f[u] 和修成的值
      {
      	f[u] = state;
      	while (u) {
      		update(u);
      		u >>= 1;
      	}
      }
      int main()
      {
      	// existing code...
      	// 離散化
      	for (int i = 1; i <= n; ++i) {
      		pos[a[i]].push_back(i);
      	}
      	for (auto x: query) { // 處理問(wèn)詢,query為排序+離散化后問(wèn)詢數(shù)組
      		reverse(pos[x].begin(), pos[x].end());
      		for (auto i: pos[x]) modify(i, 1);
      		ans[x] = dp[1][1];
      		for (auto i: pos[x]) modify(i, 2);
      	}
      	for (int i = 1; i <= q; ++i) {
      		cout << ans[m[i]] << '\n';
      	}
      

      AC 代碼

      #include <bits/stdc++.h>
      using namespace std;
      #define int long long
      #define ls u << 1
      #define rs u << 1 | 1
      const int N = 2e5 + 5, M = 4e5 + 5;
      const int INF = 1e18;
      int med(int a, int b, int c) { return a ^ b ^ c ^ min({a, b, c}) ^ max({a, b, c}); }
      int p(int m, int x) { return m < x ? 0 : m == x ? 1 : 2; }
      int n, q;
      vector<int> a(N), c(N);
      vector<int> ans(M);
      vector<int> f(M); // f[i]=p(m,i)
      int dp[M][3];
      // 更新使節(jié)點(diǎn)u的近似中位數(shù)為m的最小代價(jià)
      void update(int u)
      {
      	// 將 a[u] 修改為一個(gè)  <m    =m    >m   的數(shù)的代價(jià)
      	vector<int> cost = {c[u], c[u], c[u]};
      	cost[f[u]] = 0;
      
      	if (ls > n) { // 葉子結(jié)點(diǎn)
      		for (int i = 0; i < 3; ++i) dp[u][i] = cost[i];
      		return ;
      	}
      
      	dp[u][0] = dp[u][1] = dp[u][2] = INF;
      	for (int i = 0; i < 3; ++i) {
      		for (int j = 0; j < 3; ++j) {
      			for (int k = 0; k < 3; ++k) {
      				int mod = med(i, j, k);
      				dp[u][mod] = min(dp[u][mod], dp[ls][i] + dp[rs][j] + cost[k]);
      			}
      		}
      	}
      }
      // update the dp-tree's change due to
      // f[u]'s change, which implies a change in cost_u[0/1/2]
      void modify(int u, int state)
      {
      	f[u] = state;
      	while (u) {
      		update(u);
      		u >>= 1;
      	}
      }
      signed main()
      {
      	ios::sync_with_stdio(false);
      	cin.tie(0);
      	cin >> n;
      	for (int i = 0; i <= n; ++i) {
      		for (int j = 0; j < 3; ++j) {
      			dp[i][j] = INF;
      		}
      	}
      	vector<int> all;
      	for (int i = 1; i <= n; ++i) {
      		cin >> a[i] >> c[i];
      		all.push_back(a[i]);
      	}
      	cin >> q;
      	vector<int> m(q + 1);
      	for (int i = 1; i <= q; ++i) {
      		cin >> m[i];
      		all.push_back(m[i]);
      	}
      	// printf("a: ");
      	// for (int i = 1; i <= n; ++i) printf("%lld ", a[i]);
      	// printf("\n");
      	// printf("m: ");
      	// for (int i = 1; i <= q; ++i) printf("%lld ", m[i]);
      	// printf("\n");
      
      	// 離散化
      	sort(all.begin(), all.end());
      	all.erase(unique(all.begin(), all.end()), all.end());
      	int cnt = 1;
      	map<int, int> corr;
      	for (auto i: all) {
      		corr[i] = cnt++;
      	}
      	map<int, vector<int>> pos;
      	for (int i = 1; i <= n; ++i) {
      		a[i] = corr[a[i]];
      		pos[a[i]].push_back(i);
      	}
      	for (int i = 1; i <= q; ++i) {
      		m[i] = corr[m[i]];
      	}
      	// printf("a: ");
      	// for (int i = 1; i <= n; ++i) printf("%lld ", a[i]);
      	// printf("\n");
      	// printf("m: ");
      	// for (int i = 1; i <= q; ++i) printf("%lld ", m[i]);
      	// printf("\n");
      
      	vector<int> query;
      	for (int i = 1; i <= q; ++i) {
      		query.push_back(m[i]);
      	}
      	sort(query.begin(), query.end());
      	query.erase(unique(query.begin(), query.end()), query.end());
      
      
      	// initialize dp to all '>'s
      	for (int i = n; i > 0; --i) {
      		// modify(i, 0); unnecessary cuz it's alr all 0s
      		update(i);
      	}
      	// for (int i = 1; i < cnt; ++i) {
      	// 	printf("dp[%lld]: {%lld, %lld, %lld}\n", i, dp[i][0], dp[i][1], dp[i][2]);
      	// }
      	for (int x = 1; x < cnt; ++x) {
      		reverse(pos[x].begin(), pos[x].end());
      		for (auto i: pos[x]) {
      			modify(i, 1);
      		}
      		ans[x] = dp[1][1];
      		for (auto i: pos[x]) {
      			modify(i, 2);
      		}
      		// for (int i = 1; i < cnt; ++i) {
      		// 	printf("dp[%lld]: {%lld, %lld, %lld}\n", i, dp[i][0], dp[i][1], dp[i][2]);
      		// }
      	}
      	for (int i = 1; i <= q; ++i) {
      		cout << ans[m[i]] << '\n';
      	}
      	return 0;
      }
      

      進(jìn)食后人

      在執(zhí)行修改dp操作時(shí),要把 \(a\)\(m\) 所有元素都遍歷到,確保大小關(guān)系的正確性,防止有數(shù)值未更新。
      這點(diǎn)尤其坑,因?yàn)槿绻阒槐闅v \(m\) 的話,樣例是 可以過(guò) 的,并且總共能 A掉 \(3\)個(gè)點(diǎn),喜提\(16\text{pts}\)
      一定要初始化問(wèn)詢?yōu)?。
      不僅如此,這個(gè)初始化必須逆序。(我卡了大概10min吧

      posted @ 2025-08-28 11:41  peter_code  閱讀(18)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 91老肥熟女九色老女人| 日韩欧美人妻一区二区三区| 天堂av在线一区二区| 国产成人综合亚洲欧美日韩| 夜夜影院未满十八勿进| 国产精品1区2区3区在线观看| 久久久久夜夜夜精品国产| 精品人妻少妇嫩草av系列| 亚洲美女高潮不断亚洲| 国产欧美日韩精品丝袜高跟鞋 | 亚洲日本中文字幕天天更新| 亚洲VA中文字幕无码久久| 都安| 精品视频国产狼友视频| 色噜噜亚洲男人的天堂| 97精品尹人久久大香线蕉| 国产精品一区二区三区黄| 精品国产美女av久久久久| 丰满少妇高潮无套内谢| 日本深夜福利在线观看| 国产伦一区二区三区视频| 东京一本一道一二三区| 少妇爆乳无码专区| 精品人妻码一区二区三区| 亚洲精品中文字幕在线观| 99riav精品免费视频观看| 无码人妻精品一区二区三区蜜桃| 国产精品国产精品无卡区| 五月婷婷开心中文字幕| 国内精品久久久久影院网站 | 成人啪啪高潮不断观看| 国内不卡的一区二区三区| caoporn免费视频公开| 国产欧美日韩精品第二区| 国产av熟女一区二区三区| 成人精品视频一区二区三区| 性色av无码久久一区二区三区| 黑人巨大亚洲一区二区久| 欧美特级午夜一区二区三区| 国产精品中文字幕综合| 少妇爽到呻吟的视频|