[洛谷P5163][題解]WD 與地圖
阿新 • • 發佈:2021-12-10
暑假 wzy 鴿鴿講的自己出的題現在才抽時間補,大慚愧。
首先如果這個題是無向圖那麼就秒了,可惜不是。那麼區別在哪裡?我們發現一條有向邊加入後連線的兩個點可能會在更晚的一個時間點才強連通,不能直接並查集合並。
不過很容易發現這個東西是具有二分性的,於是我們秒掉了單個詢問。
那多個詢問怎麼辦呢?我們不能每次都 \(O(n\log n)\) 二分一遍,所以考慮整體二分。
具體來說,對於當前二分割槽間和詢問區間,我們把中點以前的點加進去跑一遍 Tarjan,用可撤銷並查集維護強連通關係。對於已經強連通的點進入左區間,否則還不強連通,進入右區間。
具體實現比較考驗技巧和耐心,可以參考混亂的程式碼:
注意空間不要太大也不要太小,考慮好每個陣列的用途再開空間。我因為懶看一直 RE 就直接往大里開了,不要學習這種行為
內容來自_ajthreac_的部落格(https://www.cnblogs.com/juruoajh/),未經允許,不得轉載。const int N=400010; int n,m,Q,a[N],t[N<<2],cnt;map<pii,int> qwq; struct Edge { int to,nxt; }e[N<<1]; int hd[N],cn; il void ade(int u,int v){ e[++cn].to=v,e[cn].nxt=hd[u],hd[u]=cn; } struct Query { int opt,u,v,tm; bool operator < (const Query &rhs)const{ return tm==rhs.tm?opt<rhs.opt:tm<rhs.tm; } }q[N<<1],p[N<<1]; int f[N],siz[N];stack<pii > stk; int F(int k){ return f[k]==k?k:F(f[k]); } void Unify(int u,int v){ u=F(u),v=F(v);if(u==v)return; if(siz[u]<siz[v])swap(u,v); f[v]=u,siz[u]+=siz[v],stk.push(mkp(u,v)); } il void Delete(int lmt){ while(stk.size()>lmt){ pii u=stk.top();stk.pop(); f[u.y]=u.y,siz[u.x]-=siz[u.y]; } } int dfn[N],low[N],tim;bool vis[N];stack<int> st; void Tarjan(int u){ dfn[u]=low[u]=++tim,vis[u]=1,st.push(u); for(int i=hd[u];i;i=e[i].nxt){ int v=e[i].to; if(!dfn[v])Tarjan(v),low[u]=min(low[u],low[v]); else if(vis[v])low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ while(st.top()!=u){ int v=st.top();st.pop(),vis[v]=0,Unify(u,v); } vis[st.top()]=0,st.pop(); } } Query ql[N<<1],qr[N<<1]; void Solve(int l,int r,int L,int R){ if(L>R)return; if(l==r){ for(int i=L;i<=R;i++)q[i].tm=l; return; } vector<int> nd;int qlt=0,qrt=0,lst=stk.size(); for(int i=L;i<=R;i++){ if(q[i].tm>nmid)continue; int u=F(q[i].u),v=F(q[i].v); nd.pub(u),nd.pub(v),ade(u,v); } for(int i:nd)if(!dfn[i])Tarjan(i); for(int i=L;i<=R;i++){ if(q[i].tm<=nmid&&F(q[i].u)==F(q[i].v))ql[++qlt]=q[i]; else qr[++qrt]=q[i]; } for(int i=1;i<=qlt;i++)q[L+i-1]=ql[i]; for(int i=1;i<=qrt;i++)q[L+i+qlt-1]=qr[i]; cn=tim=0; for(int i:nd)hd[i]=dfn[i]=low[i]=0; Solve(nmid+1,r,L+qlt,R),Delete(lst); Solve(l,nmid,L,L+qlt-1); } struct Node { int l,r,cnt,w; }tr[N*20]; int rt[N],tot; il void Pushup(int k){ tr[k].cnt=tr[ls].cnt+tr[rs].cnt; tr[k].w=tr[ls].w+tr[rs].w; } void Modify(int &k,int pos,int v,int l,int r){ if(!k)k=++tot; tr[k].cnt+=v,tr[k].w+=v*t[pos]; if(l==r)return; if(pos<=nmid)Modify(ls,pos,v,l,nmid); else Modify(rs,pos,v,nmid+1,r); } LL Query(int k,int v,int l,int r){ if(tr[k].cnt<=v)return tr[k].w; if(l==r)return t[l]*v; if(v<=tr[rs].cnt)return Query(rs,v,nmid+1,r); else return tr[rs].w+Query(ls,v-tr[rs].cnt,l,nmid); } int Merge(int u,int v,int l,int r){ if(!u||!v)return u+v; if(l==r){ tr[u].cnt+=tr[v].cnt,tr[u].w+=tr[v].w;return u; } tr[u].l=Merge(tr[u].l,tr[v].l,l,nmid); tr[u].r=Merge(tr[u].r,tr[v].r,nmid+1,r); return Pushup(u),u; } int ans[N]; signed main(){ Read(n),Read(m),Read(Q); for(int i=1;i<=n;i++)f[i]=i,siz[i]=1; for(int i=1;i<=n;i++)Read(a[i]),t[++cnt]=a[i]; for(int i=1;i<=m;i++){ Read(q[i].u),Read(q[i].v),qwq[mkp(q[i].u,q[i].v)]=i; } for(int i=1,u,v;i<=Q;i++){ Read(p[i].opt),Read(u),Read(v),p[i].tm=Q-i+1; p[i].u=u,p[i].v=v; if(p[i].opt==1)q[qwq[mkp(u,v)]].tm=p[i].tm; else if(p[i].opt==2)a[u]+=v,cnt++,a[cnt]=t[cnt]=a[u]; } sort(t+1,t+1+cnt);int tmp=unique(t+1,t+1+cnt)-t-1; Solve(0,Q+1,1,m); for(int i=1;i<=n;i++)f[i]=i,siz[i]=1; for(int i=1;i<=n;i++){ int qwq=lower_bound(t+1,t+1+tmp,a[i])-t; Modify(rt[i],qwq,1,1,tmp); } for(int i=1;i<=Q;i++)if(p[i].opt!=1)q[++m]=p[i]; sort(q+1,q+m+1); for(int i=1;i<=m;i++){ int u=q[i].u,v=q[i].v; if(q[i].opt==0){ u=F(u),v=F(v); if(u==v)continue; if(siz[u]<siz[v])swap(u,v); siz[u]+=siz[v],f[v]=u; rt[u]=Merge(rt[u],rt[v],1,tmp); }else if(q[i].opt==2){ int fa=F(u); int qwq=lower_bound(t+1,t+1+tmp,a[u])-t; a[u]-=v; int awa=lower_bound(t+1,t+1+tmp,a[u])-t; Modify(rt[fa],qwq,-1,1,tmp); Modify(rt[fa],awa,1,1,tmp); }else { int fa=F(u); ans[Q-q[i].tm+1]=Query(rt[fa],v,1,tmp); } } for(int i=1;i<=Q;i++){ if(p[i].opt==3)printf("%lld\n",ans[i]); } KafuuChino HotoKokoa }