1 条题解
-
0
自动搬运
来自洛谷,原作者为

gdf_yhm
智者搭桥,愚者筑墙。搬运于
2025-08-24 23:12:51,当前版本为作者最后更新于2025-04-13 16:20:57,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
会了 后以为过不了就去晚自习了!不过不同的手法还是有巨大差别的。
思路
强制在线。删边分裂是最大的问题,考虑根号重构。
最开始想的是按时间分块,每 个操作一块。每进入一块之前重构整个图。重构时,并查集加入部分之前的边,但不加入之前的边中前 大的。加入删除时,不修改并查集,这样就算删边也删不到在图中的边。询问时,加入剩下的边,查询,再撤销,需要可撤销并查集。常数有点爆炸,口胡完就下播了。
后来又想到更好的重构方式。重构时,按边从小到大排序加入并查集。加入时,把新边加入一个 set 中,不修改并查集。删除时,要么删 set 中一个元素,要么撤销最后一次并查集加边。当 set 中元素个数 时,把边重新排序,重构,至多 次。
至于处理答案,即把连通块大小排序后两两配对,在并查集操作时修改每个并查集大小的数量。一开始想用权值线段树维护区间的 ,被卡常了。注意到只有 种本质不同的 ,直接维护是哪些数即可。
复杂度 $O(q\log n+q(B\log n+\sqrt n\log n)+\frac{q}{B}n\log n)$。
code
int n,q; int t[maxn],id[maxn],pos[maxn],idx,tmp[maxn]; void upd(int p,int w){ t[p]+=w; if(t[p]==w)id[++idx]=p,pos[p]=idx; if(t[p]==0)pos[id[idx]]=pos[p],id[pos[p]]=id[idx],idx--; } void clr(){ while(idx)t[id[idx]]=0,idx--; } int calc(){ for(int i=1;i<=idx;i++)tmp[i]=id[i]; sort(tmp+1,tmp+idx+1); int ans=0; for(int i=idx,op=0;i;i--)if(t[tmp[i]]&1)ans+=tmp[i]*(!op?1:-1),op^=1; return ans; } int f[maxn],siz[maxn]; int fd(int x){ if(f[x]==x)return x; return fd(f[x]); } int st[maxm],tp; void merge(int u,int v){ u=fd(u),v=fd(v); if(u==v){st[++tp]=0;return ;} if(siz[u]<siz[v])swap(u,v); upd(siz[u],-1),upd(siz[v],-1); st[++tp]=v;f[v]=u,siz[u]+=siz[v]; upd(siz[u],1); } void del(){ int v=st[tp],u=f[st[tp]];tp--; if(!v)return ; upd(siz[u],-1); f[v]=v,siz[u]-=siz[v]; upd(siz[u],1),upd(siz[v],1); } tuple<int,int,int> e[maxm],e1[maxm],e2[maxm];int m,m1,m2; set<tuple<int,int,int>> s; void init(){ for(int i=1;i<=n;i++)f[i]=i,siz[i]=1;tp=0; clr();upd(1,n); } void rebuild(){ m1=0;for(auto p:s)e1[++m1]=p; m2=0;for(int i=1;i<=m;i++)e2[++m2]=e[i]; s.clear(); int p=1,q=1;m=0; while(p<=m1&&q<=m2){ if(e1[p]<=e2[q])e[++m]=e1[p++]; else e[++m]=e2[q++]; } while(p<=m1)e[++m]=e1[p++]; while(q<=m2)e[++m]=e2[q++]; init(); for(int i=1;i<=m;i++)merge(get<1>(e[i]),get<2>(e[i])); } void work(){ n=read();q=read();init(); while(q--){ char op=readc(); if(op=='a'){ int u=read(),v=read(),w=read(); s.insert({w,u,v}); } if(op=='r'){ if(!s.size()||(*--s.end())<=e[m])del(),m--; else s.erase(--s.end()); } if(op=='d'){ if(s.size()>B)rebuild(); int lst=tp; for(auto[w,u,v]:s)merge(u,v); printf("%d\n",calc());fflush(stdout); while(tp>lst)del(); } } }
- 1
信息
- ID
- 11897
- 时间
- 4500ms
- 内存
- 2048MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者