【JZOJ A組】跑商
阿新 • • 發佈:2018-11-08
Description
題目背景:
尊者神高達很窮,所以他需要跑商來賺錢
題目描述:
基三的地圖可以看做 n 個城市,m 條邊的無向圖,尊者神高達會從任意一個點出發並在起點購買貨物,在旅途中任意一點賣出並最終到達終點,尊者神高達的時間很寶貴,所以他不會重複經過同一個城市,但是為了掙錢,他可能會去繞路。當然,由於工作室氾濫,所以一個城市的貨物價格可能會發生改變。但是尊者神高達智商不足,他可能在一個很蠢的節點把貨物賣掉,所以尊者神高達想知道每一次跑商最多能賠多少錢。
Input
第一行 n,m;
接下來 1 行 n 個數,代表每個城市貨物的價格;
接下來 m 行 u,v 代表一條邊
接下來 1 行 Q
接下來 Q 行
C x w 代表城市 x 的貨物價格變為 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 都聯通,起點購買價格為 2,在 1 點賣出賠得最多2-1=1
更新後每個點價值為 5,2,3
起點價格為 5,在 2 點賣出賠得最多,5-2=3
Data Constraint
40%的資料為一棵樹
另外 20%的資料沒有修改操作
所以資料滿足 n,m,q<=100000;保證圖聯通,資料合法
思路
建一棵廣義圓方樹
每個方點記錄左右與其相連的原點的最小值
然後發現如果是棵菊花樹就炸了
所以方點的值改為記錄環上除根外權值最小的點。如果 LCA是方點,只需特判一下方點的父親。這樣修改就是 o(2)的了
程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<set> #define maxn 2000010 using namespace std; struct E { int to,next; }e[maxn*2],ee[maxn*2]; int n,m,v[maxn],num1,num2,cnt,cnt1,dfn[maxn],low[maxn],list[maxn],list1[maxn],top[maxn],dep[maxn],fa[maxn],size[maxn],son[maxn],l[2*maxn][2],p[2*maxn],tree[maxn],n2,mn[2*maxn],q[maxn]; multiset<int>Q[maxn]; using namespace std; void add(int x,int y) { e[++cnt].to=y; e[cnt].next=list[x]; list[x]=cnt; } void add1(int x,int y) { ee[++cnt1].to=y; ee[cnt1].next=list1[x]; list1[x]=cnt1; } void tarjan(int x,int fa) { q[++q[0]]=x,dfn[x]=low[x]=++dfn[0]; for(int i=list[x]; i; i=e[i].next) if(e[i].to!=fa) { if(!dfn[e[i].to]) { tarjan(e[i].to,x); if(low[e[i].to]>=dfn[x]) { add1(++num1,x),add1(x,num1); while(q[q[0]]!=e[i].to) add1(num1,q[q[0]]),add1(q[q[0]],num1),q[q[0]--]=0; add1(num1,e[i].to),add1(e[i].to,num1),q[q[0]--]=0; } else low[x]=min(low[x],low[e[i].to]); } else low[x]=min(low[x],dfn[e[i].to]); } } void dfs(int x,int pre) { dep[x]=dep[pre]+1,fa[x]=pre,size[x]=1; if(x<=n&&pre>n) Q[pre].insert(v[x]); for(int i=list1[x]; i; i=ee[i].next) if(ee[i].to!=pre) { dfs(ee[i].to,x),size[x]+=size[ee[i].to]; if(size[ee[i].to]>size[son[x]]) son[x]=ee[i].to; } } void build(int d,int x,int y) { mn[d]=1e9; if(x==y) { tree[x]=d; return; } int mid=(x+y)>>1; p[l[d][0]=++num2]=d,build(num2,x,mid); p[l[d][1]=++num2]=d,build(num2,mid+1,y); } void ins(int x,int y) { mn[x]=y,x=p[x]; while(x) mn[x]=min(mn[l[x][0]],mn[l[x][1]]),x=p[x]; } void dfs1(int x) { if(!x) return; dfn[x]=++dfn[0]; if(x>n) v[x]=*Q[x].begin(); ins(tree[dfn[x]],v[x]); top[son[x]]=top[x],dfs1(son[x]); for(int i=list1[x]; i; i=ee[i].next) if(ee[i].to!=fa[x]&&ee[i].to!=son[x]) top[ee[i].to]=ee[i].to,dfs1(ee[i].to); } int query(int d,int L,int R,int x,int y) { if(!d||x>y||x>R||y<L) return 1e9; if(x<=L&&R<=y) return mn[d]; int mid=(L+R)>>1; return min(query(l[d][0],L,mid,x,y),query(l[d][1],mid+1,R,x,y)); } int work(int x,int y) { if(top[x]==top[y]) { if(dep[x]>dep[y]) swap(x,y); int k=1e9; if(x>n) k=v[fa[x]]; return min(k,query(1,1,num1,dfn[x],dfn[y])); } if(dep[top[x]]>dep[top[y]]) swap(x,y); return min(work(x,fa[top[y]]),query(1,1,num1,dfn[top[y]],dfn[y])); } int main() { freopen("paoshang.in","r",stdin),freopen("paoshang.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) scanf("%d",&v[i]); for(int i=1,x,y; i<=m; i++) scanf("%d%d",&x,&y),add(x,y),add(y,x); num1=n,tarjan(1,0); dfs(1,0); num2=1,build(1,1,num1); memset(dfn,0,sizeof(dfn)),dfs1(1); int x,y,o; scanf("%d",&o); while(o--) { scanf("\n"); char ch=getchar(); scanf("%d%d",&x,&y); if(ch=='Q') printf("%d\n",v[x]-work(x,y)); else { ins(tree[dfn[x]],y); if(x>1) { int k=fa[x]; Q[k].erase(Q[k].find(v[x])),Q[k].insert(y); int o=*Q[k].begin(); if(v[k]!=o) v[k]=o,ins(tree[dfn[k]],v[k]); } v[x]=y; } } }