【学习笔记】CF603E Pastoral Oddities

先不考虑数据结构部分,尝试猜一下结论。

结论:一个连通块有解当且仅当连通块的度数为偶数。

然后这题要你最大边权最小。最无脑的方法就是直接上 lct \text{lct} lct真省事啊

我第一眼想到的还是整体二分。这玩意非常好写。

但是为什么也可以用线段树分治来做呢。这需要简单的分析一下性质。考虑求出每条边在哪些生成树上出现过,分析可知这一定是一段区间。

然后是非常玄学的操作。考虑离线,然后 倒着处理询问 (真是违背常理啊),这样的话一条边如果原来在生成树上,那么删去一条边后显然还是在生成树上(上面的分析告诉你的),这意味着恰好有一条边被加了进去,而这条边被加进去的条件就是连接的两个点不联通。

基于上述分析,我们可以尝试分治。首先,计算出影响区间的右端点在 [ m i d + 1 , r ] [mid+1,r] [mid+1,r]之间的边,那么我们就要先算出哪些边的影响区间 ≥ m i d + 1 \ge mid+1 mid+1,哪些边的影响区间 ≤ m i d \le mid mid,这样就将边集分成了两部分。使用可撤销并查集,然后往两边递归即可。怎么计算答案呢,发现递归到叶子节点的时候可以把那颗生成树算出来,然后就做完了。

事实上算边的影响区间部分我们可以不用真的将边分到两个集合中去。考虑更聪明的想法,倒着往前处理询问的时候,之前在生成树上的边还是在生成树上,那么我们事实上只需要在此基础上加入边权更大的边(当然这条边必须合法),直到得到的图满足条件。那么我们就知道新加入的这些边的影响区间的右端点就是当前这个位置,在线段树上对应部分打一个标记即可。这个半在线做法非常神奇。

这高级玩意估计考场上也想不到/kk

复杂度 O ( n log ⁡ n log ⁡ m ) O(n\log n\log m) O(nlognlogm)

实现了后一种较为复杂的方法。

该死,有一个地方打挂了。

#include<bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define inf 0x3f3f3f3f #define db double #define cpx complex<db> using namespace std; const int N=3e5+5; int n,m,cnt,res[N],now; int fa[N],s[N],sa[N]; vector<int>G[N<<2]; struct node{ int x,y,z; }e[N]; bool cmp(int x,int y){ return e[x].z<e[y].z; } int find(int x){ return fa[x]==x?x:find(fa[x]); } void modify(int p,int l,int r,int ql,int qr,int x){ if(ql>qr)return; if(ql<=l&&r<=qr){ G[p].pb(x); return; } int mid=l+r>>1; if(ql<=mid)modify(p<<1,l,mid,ql,qr,x); if(mid<qr)modify(p<<1|1,mid+1,r,ql,qr,x); } void solve(int p,int l,int r){ vector<pair<int,int>>bak; for(auto pos:G[p]){ int x=find(e[pos].x),y=find(e[pos].y); if(x!=y){ cnt-=(s[x]&1)+(s[y]&1); if(s[x]>s[y])swap(x,y); bak.pb(make_pair(x,y)); fa[x]=y,s[y]+=s[x],cnt+=(s[y]&1); } } if(l==r){ while(cnt&&now<=m){ int x=find(e[sa[now]].x),y=find(e[sa[now]].y); if(sa[now]<l)modify(1,1,m,sa[now],l-1,sa[now]);//fixed if(sa[now]<=l&&x!=y){ cnt-=(s[x]&1)+(s[y]&1); if(s[x]>s[y])swap(x,y); bak.pb(make_pair(x,y)); fa[x]=y,s[y]+=s[x],cnt+=(s[y]&1); } now++; } if(!cnt)res[l]=e[sa[now-1]].z; else res[l]=-1; } else{ int mid=l+r>>1; solve(p<<1|1,mid+1,r); solve(p<<1,l,mid); } reverse(bak.begin(),bak.end()); for(auto x:bak){ cnt-=s[x.se]&1; fa[x.fi]=x.fi,s[x.se]-=s[x.fi]; cnt+=(s[x.fi]&1)+(s[x.se]&1); } } int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>m;for(int i=1;i<=n;i++)fa[i]=i,s[i]=1; for(int i=1;i<=m;i++){ cin>>e[i].x>>e[i].y>>e[i].z,sa[i]=i; } sort(sa+1,sa+1+m,cmp); cnt=n,now=1; solve(1,1,m); for(int i=1;i<=m;i++)cout<<res[i]<<"\n"; }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17529992.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(5)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示