【最小生成树&LCT】Codeforces603E-Pastoral Oddities
来源:互联网 发布:易观外卖大数据 编辑:程序博客网 时间:2024/04/27 12:04
题目大意:
给出一个图,求使得这个图中每个点的度数都为奇数。
求出用前i条边,使图满足条件的情况下,最大边权的最小值。
分析:
SolutionA LCT维护最小生成树
很容易发现一些性质:
如果要使得图中每个点度数为奇数,那么每个联通块中点的个数一定为偶数:
根据题目,为了使最大边权最小,我们可以把每个联通块看成它的最小生成树,那么这棵树一定满足:每个非根节点的儿子结点个数必须为偶数,根节点儿子结点个数必为奇数。否则就会出现度数为奇的情况。
那么我们可以这么考虑:首先根节点的儿子结点个数为奇,那么加上他自己,与根节点直接相连的点的个数就为偶数。每个非根结点都会为树增加偶数个子节点,所以最终整个树上的点一定为偶数个。
为了使图中的所有联通块大小都为偶数,
我们可以发现,加边是绝对无害的:
因为:奇数图+奇数图=偶数图,奇数图+偶数图=奇数图,偶数图+偶数图=偶数图。
所以可见我们要尽量加边。
当然,如果边的两端在同一联通块,我们就要找到环上的最大边权,与当前边权比较,看能否替换掉。
满足每个点度数都为奇数后,
为了使最大边权尽量小,我们也必须拆边,显然,拆边不能使图中生成奇数图,所以每次删去最大的边,再判断一次是否合法即可。
现在,我们需要动态地插边和删边,并询问路径上的最大边权,以及询问联通块大小。能做到的这些操作的数据结构,显然使用LCT。
#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<set>#define SF scanf#define PF printfusing namespace std;void Read(int &x){ char c; bool flag=0; while(c=getchar(),c!=EOF&&(c<'0'||c>'9')&&c!='-'); if(c=='-'){c=getchar();flag=1;} x=c-'0'; while(c=getchar(),c!=EOF&&c>='0'&&c<='9')x=x*10+c-'0'; if(flag==1)x=-x;}#define MAXN 100010#define MAXM 400010namespace LCT{ int fa[MAXM],son[MAXM][2]; bool pre[MAXM],rev[MAXM]; int siz[MAXM],maxi[MAXM],val[MAXM],w[MAXM],sum[MAXM],mpos[MAXM]; void update(int x){ sum[x]=sum[son[x][0]]+sum[son[x][1]]+w[x]; siz[x]=siz[son[x][0]]+siz[son[x][1]]+1; maxi[x]=val[x]; mpos[x]=x; if(maxi[son[x][0]]>maxi[x]) maxi[x]=maxi[son[x][0]],mpos[x]=mpos[son[x][0]]; if(maxi[son[x][1]]>maxi[x]) maxi[x]=maxi[son[x][1]],mpos[x]=mpos[son[x][1]]; } void flip(int x){ swap(son[x][0],son[x][1]); rev[x]^=1; } void pushdown(int x){ if(rev[x]){ flip(son[x][0]); flip(son[x][1]); } rev[x]=0; } void rotate(int x,int d){ int y=fa[x]; fa[x]=fa[y]; pre[x]=pre[y]; if(fa[y]&&pre[y]) son[fa[y]][son[fa[y]][1]==y]=x; pre[y]=1; son[y][!d]=son[x][d]; if(son[x][d]) fa[son[x][d]]=y; son[x][d]=y; fa[y]=x; update(y); update(x); } int sta[MAXM]; void splay(int x){ int y,z; int pnt=0; int x1=x; while(pre[x1]) sta[++pnt]=x1,x1=fa[x1]; sta[++pnt]=x1; for(int i=pnt;i>0;i--) pushdown(sta[i]); while(pre[x]){ y=fa[x]; z=fa[y]; if(!pre[y]){ rotate(x,son[y][0]==x); break; } if((son[z][0]==y)==(son[y][0]==x)){ rotate(y,son[z][0]==y); rotate(x,son[y][0]==x); } else{ rotate(x,son[y][0]==x); rotate(x,son[z][0]==x); } } if(rev[x]) flip(x); update(x); } int Access(int x){ int last=0; while(x){ splay(x); pre[son[x][1]]=0; fa[son[x][1]]=x; w[x]+=sum[son[x][1]]; son[x][1]=last; if(last) pre[last]=1; w[x]-=sum[last]; update(x); last=x; x=fa[last]; } return last; } void MakeRoot(int x){ flip(Access(x)); splay(x); rev[x]=!rev[x]; } int FindRoot(int x){ Access(x); splay(x); int u=x; while(son[u][0]){ pushdown(u); u=son[u][0]; } splay(u); return u; } void Link(int x,int y){ if(FindRoot(x)==FindRoot(y)) return ; flip(Access(x)); splay(x); flip(Access(y)); splay(y); fa[x]=y; w[y]+=sum[x]; sum[y]+=sum[x]; Access(x); } void Change(int x,int y){ val[x]=y; Access(x); } void Cut(int x){ Access(x); splay(x); pre[son[x][0]]=0; fa[son[x][0]]=0; son[x][0]=0; update(x); } void Cut(int x,int y){ flip(Access(x)); Cut(y); } int Query(int x,int y){ flip(Access(x)); return maxi[Access(y)]; } int Road(int x,int y){ flip(Access(x)); return mpos[Access(y)]; } int Size(int x){ Access(x); splay(x); return sum[x]; }}using namespace LCT;int lu[MAXM],lv[MAXM];int odd,n,m;void prepare(){ for(int i=1;i<=n+m;i++){ siz[i]=1; if(i<=n) w[i]=1,sum[i]=1; }}void addedge(int idx){ int u=lu[idx]; int v=lv[idx]; if(Size(u)%2==1&&Size(v)%2==1) odd-=2; Link(n+idx,u); Link(n+idx,v);}int deledge(int idx){ int u=lu[idx]; int v=lv[idx]; Cut(n+idx,u); Cut(n+idx,v); //PF("(%d %d %d %d)\n",Size(u),Size(v),u,v); if(Size(u)%2==1&&Size(v)%2==1) odd+=2; return !(Size(u)%2);}set<pair<int,int>,greater<pair<int,int> > > q;pair<int,int> l[MAXM];int main(){ Read(n),Read(m); prepare(); int x,y,wt; odd=n; for(int i=1;i<=m;i++){ Read(lu[i]),Read(lv[i]),Read(l[i].first); l[i].second=i; int u=lu[i]; int v=lv[i]; val[i+n]=maxi[i+n]=l[i].first; if(FindRoot(u)==FindRoot(v)){ int qs=Road(u,v); if(val[qs]>l[i].first){ deledge(qs-n); addedge(i); q.erase(q.find(make_pair(l[qs-n].first,qs-n))); q.insert(l[i]); //PF("{%d %d}\n",q.size(),q.begin()->id); } } else{ addedge(i); q.insert(l[i]); } //PF("(%d]\n",odd); if(odd){ PF("-1\n"); continue; } while(deledge(q.begin()->second)) q.erase(q.begin()); addedge(q.begin()->second); PF("%d\n",q.begin()->first); }}
阅读全文
0 0
- 【最小生成树&LCT】Codeforces603E-Pastoral Oddities
- [LCT维护最小生成树 || CDQ分治 || 线段树 并查集 dfs树] Codeforces 603E #334 (Div. 1) E. Pastoral Oddities
- [分治][并查集]Codeforces 603E. Pastoral Oddities
- BZOJ 2594 LCT维护最小生成树
- LCT+最小生成树+并查集+离线(BZOJ2594)
- [BZOJ3669]NOI2014魔法森林|LCT|最小生成树
- bzoj 2594 水管局长 | LCT | 最小生成树
- 【最小生成树】【LCT】【bzoj2594】水管局长数据加强版
- 【NOI2014T2】魔法森林-LCT维护最小生成树
- [GCD最小生成树 LCT] HDU5398 .GCD TREE
- [2017纪中10-28]图 最小生成树+LCT
- bzoj 1050 [HAOI2006]旅行comf [最小生成树] [动点spfa] [LCT]
- bzoj 2594: [Wc2006]水管局长数据加强版(LCT+最小生成树+离线)
- [最小极差生成树 LCT || 二分答案 CDQ分治 并查集] Ural 2055 Urban Geography
- BZOJ 2594: [Wc2006]水管局长数据加强版(LCT+最小生成树+离线)
- hdu5398(lct维护最大生成树)
- 最小比例 最小生成树
- 【LCT维护最大生成树】[HDU5389]GCD Tree
- 深入理解JVM
- day06<面向对象>
- python中break语句
- Password CodeForces
- (一)Web开发那些事
- 【最小生成树&LCT】Codeforces603E-Pastoral Oddities
- day07<面向对象+>
- javascript 数组以及对象的深拷贝(复制数组或复制对象)的方法
- Linux内核开发之内存与I/O访问(一)
- day08<面向对象+>
- day09<面向对象+>
- Thymeleaf 知识库
- 学习经历与求职经历分享
- webstorm安装vue插件