JZOJ 5909. 【NOIP2018模拟10.16】跑商(paoshang)
Description
題目背景:
尊者神高達(dá)很窮,所以他需要跑商來(lái)賺錢
題目描述:
基三的地圖可以看做 n 個(gè)城市,m 條邊的無(wú)向圖,尊者神高達(dá)會(huì)從任意一個(gè)點(diǎn)出發(fā)并在起點(diǎn)購(gòu)買貨物,在旅途中任意一點(diǎn)賣出并最終到達(dá)終點(diǎn),尊者神高達(dá)的時(shí)間很寶貴,所以他不會(huì)重復(fù)經(jīng)過(guò)同一個(gè)城市,但是為了掙錢,他可能會(huì)去繞路。當(dāng)然,由于工作室泛濫,所以一個(gè)城市的貨物價(jià)格可能會(huì)發(fā)生改變。但是尊者神高達(dá)智商不足,他可能在一個(gè)很蠢的節(jié)點(diǎn)把貨物賣掉,所以尊者神高達(dá)想知道每一次跑商最多能賠多少錢。
Input
第一行 n,m;
接下來(lái) 1 行 n 個(gè)數(shù),代表每個(gè)城市貨物的價(jià)格;
接下來(lái) m 行 u,v 代表一條邊
接下來(lái) 1 行 Q
接下來(lái) Q 行
C x w 代表城市 x 的貨物價(jià)格變?yōu)?w
Q u v 代表一次從 u 到 v 的跑商
Output
如題目描述
Sample Input
3 3
1 2 3
1 2
2 3
1 3
3
Q 2 3
C 1 5
Q 1 3
Sample Output
1
3
樣例解釋:
1,2,3 都聯(lián)通,起點(diǎn)購(gòu)買價(jià)格為 2,在 1 點(diǎn)賣出賠得最多2-1=1
更新后每個(gè)點(diǎn)價(jià)值為 5,2,3
起點(diǎn)價(jià)格為 5,在 2 點(diǎn)賣出賠得最多,5-2=3
Data Constraint
40%的數(shù)據(jù)為一棵樹(shù)
另外 20%的數(shù)據(jù)沒(méi)有修改操作
所以數(shù)據(jù)滿足 n,m,q<=100000;保證圖聯(lián)通,數(shù)據(jù)合法
Solution
-
40%的數(shù)據(jù)就是裸的樹(shù)鏈剖分,查詢區(qū)間最小值、單點(diǎn)修改即可。
-
而變成無(wú)向圖后呢,就要用到圓方樹(shù)了!
-
圓方樹(shù)是處理仙人掌的利器,應(yīng)用廣泛。
-
嗯,首先,它是一棵樹(shù),由圓點(diǎn)和方點(diǎn)組成。
-
原圖中就存在的點(diǎn)被稱為圓點(diǎn),我們將其縮點(diǎn)雙聯(lián)通分量后,新建一個(gè)方點(diǎn)來(lái)代表這個(gè)點(diǎn)雙,
-
并將點(diǎn)雙中的點(diǎn)與這個(gè)方點(diǎn)連邊(原來(lái)點(diǎn)雙里面的邊就不要了),縮點(diǎn)雙用 tarjan 算法。
-
建出來(lái)的圓方樹(shù)的圓點(diǎn)和方點(diǎn)是相隔的,即不會(huì)有圓點(diǎn)連圓點(diǎn)、方點(diǎn)連方點(diǎn)。
-
有了這顆圓方樹(shù),我們就能解決很多問(wèn)題了!
-
在本題中,圓點(diǎn)的權(quán)值就設(shè)為其本來(lái)的值(即 aia_iai?),而方點(diǎn)的值就是點(diǎn)雙中點(diǎn)權(quán)的最小值。
-
注意: 這里方點(diǎn)的值不包括其父親圓點(diǎn)的(這樣好算很多)。
-
于是查詢就能用樹(shù)鏈剖分求最小值了,注意若兩點(diǎn)lca是方點(diǎn),還得算上其父親圓點(diǎn)的值。
-
而查詢的話,對(duì)于該圓點(diǎn)就單點(diǎn)修改,對(duì)于其屬于的方點(diǎn)就用一個(gè)set(可維護(hù)插入刪除,求最小值的數(shù)據(jù)結(jié)構(gòu))維護(hù)其包含的圓點(diǎn)值即可。
-
時(shí)間復(fù)雜度 O(nlog2n)O(n\ log^2n)O(n?log2n) 。
Code
#include<cstdio> #include<algorithm> #include<set> #include<cctype> using namespace std; const int N=1e5+5,inf=1e9; int n,m,tot=1,num,cnt,rt,qx,qy,stop,ans; int first[N],nex[N<<1],en[N<<1]; int first1[N<<1],nex1[N<<1],en1[N<<1],d[N<<1]; int a[N]; int dfn[N],low[N],st[N],id[N]; int fa[N<<1],dep[N<<1],size[N<<1],son[N<<1]; int top[N<<1],tree[N<<1],pre[N<<1],f[N<<3]; multiset<int>ss[N<<1]; multiset<int>::iterator it; inline int read() {int X=0,w=0; char ch=0;while(!isdigit(ch)) w|=ch=='-',ch=getchar();while(isdigit(ch)) X=(X<<1)+(X<<3)+(ch^48),ch=getchar();return w?-X:X; } inline void insert(int x,int y) {nex[++tot]=first[x];first[x]=tot;en[tot]=y; } inline void insert1(int x,int y) {nex1[++tot]=first1[x];first1[x]=tot;en1[tot]=y;d[y]++; } inline int min(int x,int y) {return x<y?x:y; } void tarjan(int x,int y) {dfn[x]=low[x]=++num;st[++stop]=x;for(int i=first[x];i;i=nex[i])if(!dfn[en[i]]){tarjan(en[i],i^1);low[x]=min(low[x],low[en[i]]);if(low[en[i]]>=dfn[x]){cnt++;do{id[st[stop]]=cnt;insert1(cnt,st[stop]);ss[cnt].insert(a[st[stop]]);}while(st[stop--]^en[i]);insert1(x,cnt);}}elseif(i^y) low[x]=min(low[x],dfn[en[i]]); } void dfs(int x) {dep[x]=dep[fa[x]]+1;size[x]=1;for(int i=first1[x];i;i=nex1[i])if(en1[i]^fa[x]){fa[en1[i]]=x;dfs(en1[i]);size[x]+=size[en1[i]];if(!son[x] || size[son[x]]<size[en1[i]]) son[x]=en1[i];} } void dfs1(int x,int y) {top[pre[tree[x]=++num]=x]=y;if(!son[x]) return;dfs1(son[x],y);for(int i=first1[x];i;i=nex1[i])if(en1[i]^fa[x] && en1[i]^son[x]) dfs1(en1[i],en1[i]); } void make(int v,int l,int r) {if(l==r){if(pre[l]>n){it=ss[pre[l]].begin();f[v]=*it;}else f[v]=a[pre[l]];return;}int mid=l+r>>1;make(v<<1,l,mid);make(v<<1|1,mid+1,r);f[v]=min(f[v<<1],f[v<<1|1]); } int find(int v,int l,int r) {if(qx<=l && r<=qy) return f[v];int mid=l+r>>1;int s=inf;if(qx<=mid) s=find(v<<1,l,mid);if(qy>mid) s=min(s,find(v<<1|1,mid+1,r));return s; } void change(int v,int l,int r) {if(l==r){f[v]=qy;return;}int mid=l+r>>1;if(qx<=mid) change(v<<1,l,mid); else change(v<<1|1,mid+1,r);f[v]=min(f[v<<1],f[v<<1|1]); } int main() {freopen("paoshang.in","r",stdin);freopen("paoshang.out","w",stdout);n=cnt=read(),m=read();for(int i=1;i<=n;i++) a[i]=read();for(int i=1;i<=m;i++){int x=read(),y=read();insert(x,y);insert(y,x);}tarjan(1,tot=0);for(int i=1;i<=cnt;i++)if(!d[i]){rt=i;break;}dfs(rt);num=0;dfs1(rt,rt);make(1,1,num);int q=read();while(q--){char ch=getchar();while(ch^'Q' && ch^'C') ch=getchar();if(ch=='Q'){int x=read(),y=read(),st=a[x];ans=inf;int f1=top[x],f2=top[y];while(f1^f2){if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);qx=tree[f1],qy=tree[x];ans=min(ans,find(1,1,num));x=fa[f1],f1=top[x];}if(dep[x]>dep[y]) swap(x,y);qx=tree[x],qy=tree[y];ans=min(ans,find(1,1,num));if(x>n) ans=min(ans,a[fa[x]]);printf("%d\n",st-ans);}else{int x=read(),w=read();qx=tree[x],qy=w;change(1,1,num);int y=id[x];if(y){it=ss[y].find(a[x]);ss[y].erase(it);ss[y].insert(w);it=ss[y].begin();qx=tree[y],qy=*it;change(1,1,num);}a[x]=w;}}return 0; }總結(jié)
以上是生活随笔為你收集整理的JZOJ 5909. 【NOIP2018模拟10.16】跑商(paoshang)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: JZOJ 5904. 【NOIP2018
- 下一篇: JZOJ 5907. 【NOIP2018