巡遊tour 二分 樹分治 單調佇列

2021-07-24 07:28:37 字數 2125 閱讀 7778

【題解】二分+樹分治+單調佇列

題目大意就是要求一條路徑使得其中位數最大。首先由於答案很難直接確定,採用二分~

首先二分出可能答案mid。有了mid值之後對於每條邊w[i],若w[i]>=mid,令w[i]=1,else w[i]=-1

這樣一來,問題被轉化為樹上是否存在一條長度在[l,r]之間的非負路徑,暴力判斷即可;

二分+樹分治+線段樹:

依然如20%做法找非負路徑。但這裡採用樹分治的方法。對於每棵子樹我們只考慮經過根的路徑,其餘遞迴處理。

考慮過根的路徑。對於當前遞迴到的子樹x,依次處理其兒子子樹的資訊並與之前兒子子樹得到的資訊算出答案。那麼我們要儲存的值是什麼呢?

如果我們對於每個節點儲存乙個深度de[i],從點i到當前根節點的路徑值為sum[x],那麼對於已處理過的所有節點的深度相同的點,只需要儲存路徑最大值即可。因為相同深度的點對答案貢獻的範圍是一樣的(都在[l,r]之間),而要找非負路徑顯然最大值更優。

得到這個性質之後,考慮怎麼更新答案。遍歷當前子樹,對於每個節點u,合法的答案就是sum[u]+max(p[v]) 其中p[v]代表深度為v的路徑最大值,v代表對於當前點距離範圍在[l,r]之間的深度。而區間最大值,我們顯然能用線段樹來做。這樣每次樹分治我們構造一棵線段樹,複雜度為 o(log n),樹分治複雜度為 o(n log n),二分複雜度為 o(log n)。總時間複雜度:o(n log n^3)。

二分+樹分治+單調佇列

在60%的基礎上,我們思考能否降低查詢需求區間最大值的複雜度。如果對於當前子樹遍歷時使用廣搜,那麼深度顯然是逐漸增大的,此時我們可以用單調佇列來記錄最大值。

但是這個方法要注意,單調佇列裡儲存的最多是當前子樹的最大深度個節點,所以如果處理的第一棵子樹很大的話,複雜度容易退化。為了保證複雜度,可以在二分前先樹分治做一遍預處理,使得子樹按照深度從小到大排序。

時間複雜度:o(n log n^2);

//但是我懶,我不想打初始化,所以我樹分治加了個剪枝過的。如果當前子樹大小小於l就返回。

#include 

#include

#include

#include

#define n 100005

#define inf 1000000000

struct edgee[n<<1];

int n,l,r,cnt,ans,m,mx,rt,tot,l=1,r,w[n],fi[n],s[n],p[n],q[n],f[n],g[n],de[n],fa[n];

bool bo[n];

void add(int u,int v,int w)

void findrt(int

x)

mxx=std::max(mxx,tot-s[x]);

if (m***;

}bool work(int

x)

de[e[i].to]=1;g[1]=e[i].w;fa[e[i].to]=x;

for (q[he=ta=1]=e[i].to;he<=ta;++he)

if (h<=t && f[p[h]]+g[he]>=0) return true;

if (de[q[he]]>=r) continue;

for (int j=fi[q[he]];j;j=e[j].nxt)

}mxdp=std::max(mxdp,de[q[ta]]);

for (int j=1;j<=ta;++j) f[de[q[j]]]=std::max(f[de[q[j]]],g[j]);

}for (int i=0;i<=mxdp;++i) f[i]=-inf;

return false;

}bool dfs(int

x,int z)

return false;

}bool check(int mid)

int main()

std::sort(w+1,w+n);

mx=tot=n;findrt(1);ans=-1;

for (int i=1;i<=n;++i) f[i]=-inf;

for (r=n-1;l<=r;)

printf("%d\n",ans);

return

0;}

【題外話】我真是。。太菜了。。

尋找段落(二分 單調佇列)

題目描述 給定乙個長度為n的序列a i,定義a i 為第i個元素的價值。現在需要找出序列中最有價值的 段落 段落的定義是長度在 s,t 之間的連續序列。最有價值段落是指平均值最大的段落,段落的平均值 段落總價值 段落長度。輸入輸出格式 輸入格式 第一行乙個整數n,表示序列長度。第二行兩個整數s和t,...

中間數(二分) 單調佇列

1 中間數 mid.cpp c pas 問題描述 有n個整數 a1 an 任意兩個整數做絕對值差 ai aj 1 i 可以得到 n n 1 2 個絕對值差,令 m n n 1 2 保證m 一定是個偶數,求第 m 2小的數 輸入格式 輸入檔名為mid.in。第一行,乙個整數n 接下來n行,每行乙個整數...

二分答案 單調佇列 尋找段落

二分答案 單調佇列字首和維護 每次二分乙個平均值k,序列中的數全部減去k,如果序列中存在長度在 s,t 中且和超過0的子串行,則證明仍然有更大的平均值,到 mid,r 中找,反之,則到 l,mid 中找 這個操作用單調佇列維護 i s q tail 且 sum i s sum q tail 說明i ...