省選集訓2022 模擬賽13

2022-10-08 21:54:31 字數 3872 閱讀 4579

題目描述

有 \(n\) 個元素 \(\\),\(m\) 次詢問 \([l_i,r_i]\),問滿足 \(l_i\leq x的三元組 \((x,y,z)\),其最大的 \(a_x+a_y+a_z\) 是最少。

\(n,m\leq 5\cdot 10^5,a_i\leq 10^9\)

解法

首先考慮 \(m=1\) 怎麼做?乙個關鍵的 \(\tt observation\) 是:只有滿足 \(a_x>a_,a_...a_\),\(a_y>a_,a_...a_\) 的 \((x,y)\) 才是可能對答案有貢獻的,並且這樣的二元組只有 \(o(n)\) 對。

那麼我們可以從後往前列舉 \(x\),並且維護單調棧,那麼 \(y\) 只可能是單調棧被彈出的元素和棧頂的元素,那麼知道 \(x,y\) 之後 \(z\) 就是字尾最大值,這樣就成功解決了 \(m=1\) 的情況。

回到本題,我們把詢問掛在左端點處,只需要對 \(z\) 維護線段樹,就可以把 \(z\) 的範圍限制在 \([l_i,r_i]\),時間複雜度 \(o(n\log n)\)

總結

找結論的乙個方向是,考慮可能貢獻的元素。本題因為確定 \(x,y\) 之後才能確定 \(z\),所以必須要找結論。

此外列舉的量不要侷限,我一開始列舉 \(y\) 怎麼都想不出來,要是列舉 \(x\) 這題可能會好做得多。

單調棧的應用不止有處理 \(\max/\min\) 的功能,還可以幫助你只考慮有貢獻的資訊。

#include #include #include using namespace std;

const int m = 500005;

const int n = m<<2;

#define int long long

int read()

while(c>='0' && c<='9')

return x*f;

}void write(int x)

int n,m,tp,a[m],b[n],s[m],ans[m],tr[n],mx[n];

struct node;vectorq[m];

void build(int i,int l,int r)

int mid=(l+r)>>1;

build(i<<1,l,mid);

build(i<<1|1,mid+1,r);

tr[i]=b[i]=max(b[i<<1],b[i<<1|1]);

}void zxy(int i,int c)

void upd(int i,int l,int r,int l,int r,int c)

int mid=(l+r)>>1;

zxy(i<<1,mx[i]);zxy(i<<1|1,mx[i]);

upd(i<<1,l,mid,l,r,c);

upd(i<<1|1,mid+1,r,l,r,c);

tr[i]=max(tr[i<<1],tr[i<<1|1]);

}void add(int x,int y)

int ask(int i,int l,int r,int l,int r)

signed main()

); }

for(int i=n;i>=1;i--)

for(int i=1;i<=m;i++)

write(ans[i]),puts("");

}

題目描述

給定 \(n\) 個點 \(m\) 條邊的無向圖,邊權為 \(1\),點 \(i\) 可以花費 \(c_i\) 的代價到達所有距離 \(\leq d_i\) 的城市。保證圖聯通,求出 \(1\) 到所有點的最短路。

\(n\leq 2\cdot 10^5,c_i\leq 10^9,n-1\leq m\leq n+50\)

解法

首先考慮樹的情況怎麼做,顯然的思路是點分治優化建圖,然後跑最短路即可。

那麼對於圖的情況,我們先任取一棵生成樹,然後對其點分治優化建圖。現在非樹邊是沒有考慮到的,我們只需要讓路徑強制經過非樹邊的某個端點即可,所以我們以取非樹邊的乙個端點為根 \(\tt bfs\),然後優化建圖即可。

時間複雜度 \(o(n\log ^2n+nk\log n)\)

為了去掉複雜度中的 \(o(\log n)\) 其實有更好的方法,由於代價是點代價,所以每個點只會被訪問一次,那麼樹的情況我們可以不把圖顯式地建出來,在點分樹上維護指標即可做到 \(o(n\log n)\);\(\tt bfs\) 也可以類似地維護指標,時間複雜度 \(o(n\log n+nk)\)

下面貼上我深度卡常的法 \(1\) **,注意這個**只能獲得 \(80\) 分。

總結

點代價的最短路有其特殊性(訪問即確定,只會訪問一次),一定要注意。

#pragma gcc optimize("ofast")

#include #include #include #include #include #include #include using namespace std;

const int m = 200005;

const int n = 80*m;

#define pb push_back

#define ll long long

#define pii pairint read()

while(c>='0' && c<='9')

return x*f;

}void write(ll x)

int n,m,rt,sz,a[m],b[m],c[m],d[m],vis[m],mx[m],siz[m];

vectorg[m],g[m];int cnt,m1,m2,tot,f[n];ll dis[n];

struct edgee[n*3];

struct node

};void pre(int u,int fa)

pre(v,u);g[u].pb(v);g[v].pb(u); }}

void find(int u,int fa)

mx[u]=max(mx[u],sz-siz[u]);

if(mx[u]=d) b[++m2]=;

for(int v:g[u]) }

void add(int u,int v)

,f[u]=tot;

}void work()

if(x) add(b[i].u,x);

if(x!=lst && lst) add(x,lst);lst=x; }}

void solve(int u)

}void bfs(int s)

; if(b[u]>=d[u]) b[++m2]=;

for(int v:g[u]) if(d[v]==-1)

d[v]=d[u]+1,q.push(v); }}

void dijk()

); while(!q.empty())

); }

} }}signed main()

for(int i=1;i<=n;i++)

b[i]=read(),c[i]=read();

pre(1,0);

//work for tree

memset(vis,0,sizeof vis);

mx[rt=0]=sz=n;find(1,0);solve(1);

//work for graph

for(int i=1;i<=n;i++) if(a[i])

dijk();

for(int i=2;i<=n;i++)

write(dis[i]),puts("");

}

省選集訓2022 模擬賽6

題目描述 定義長度為 n 的好串 s 滿足 給你長度為 n 的序列 a 和 v 分別表示原序列和價值序列。你每次可以選擇乙個原序列中的好串,將其刪除之後剩下的串會前後拼接。設這次刪除的長度是 l 那麼會得分 v l 問最大得分,不一定要把原序列刪完。n leq 400,v i leq 10 5,a ...

省選集訓2022 模擬賽8

題目描述 給定乙個 n times m 的 01 矩陣,對於矩陣的每乙個位置,你需要對於這個位置上的值反轉,然後求出這個矩陣的秩的變化 0 可以將這個矩陣看成 n 個大小為 0,2 m 的數,秩就是它們線性基的大小。n,m leq 1000 解法 我們判斷求出原先的 n 個向量在原來的線性基中是可以...

省選集訓2022 模擬賽10

題目描述 給定 n 個元素,每個元素有兩個屬性值 a i,b i 我們可以將其以任意順序排列,要最大化下式 min a i i cdot k max b i i cdot k n leq 10 5,a i,b i,kn leq 10 9 解法 應該是遇到困難退大火才對,直接使用列舉法,考慮列舉 m ...