首先,一个神奇的结论:
一个合法的方案存在的条件是每一个联通块的节点数都是偶数个的.
这个可以用数学归纳法简单证一证.
证出这个后,我们只需动态加入每一个边,并查看一下有哪些边能够被删除(删掉后联通块依然合法).
对于维护加边,删边,我们用动态树.
对于枚举哪些边可以被删,我们可以用堆/set来维护.
由于每一条边最多只会加一次,也最多只会删一次,所以总时间复杂度为 $O(nlogm)$.

#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define lson t[x].ch[0]
#define rson t[x].ch[1]
#define N 500000
#define setIO(s) freopen(s".in","r",stdin) ,freopen(s".out","w",stdout)
using namespace std;
struct Edge {
int u,v,c,id;
Edge(int u=0,int v=0,int c=0,int id=0):u(u),v(v),c(c),id(id){}
bool operator<(Edge a) const{
return a.c>c;
}
}e[N];
priority_queue<Edge>q;
int sta[N],n,m,del[N];
struct Node {
int ch[2],max,val,son,size,f,id,rev;
}t[N];
int isrt(int x) {
return !(t[t[x].f].ch[0]==x||t[t[x].f].ch[1]==x);
}
int get(int x) {
return t[t[x].f].ch[1]==x;
}
void mark(int x) {
if(!x) return;
swap(lson,rson), t[x].rev^=1;
}
void pushup(int x) {
t[x].max=t[x].val,t[x].id=x;
t[x].max=max(t[x].max,max(t[lson].max,t[rson].max));
if(t[lson].max==t[x].max) t[x].id=t[lson].id;
if(t[rson].max==t[x].max) t[x].id=t[rson].id;
t[x].size=t[x].son+t[lson].size+t[rson].size+(x<=n);
}
void pushdown(int x) {
if(t[x].rev) mark(lson), mark(rson), t[x].rev=0;
}
void rotate(int x) {
int old=t[x].f,fold=t[old].f,which=get(x);
if(!isrt(old))
t[fold].ch[t[fold].ch[1]==old]=x;
t[old].ch[which]=t[x].ch[which^1],t[t[old].ch[which]].f=old;
t[x].ch[which^1]=old,t[old].f=x,t[x].f=fold;
pushup(old),pushup(x);
}
void splay(int x) {
int v=0,u=x,fa;
for(sta[++v]=u;!isrt(u);u=t[u].f) sta[++v]=t[u].f;
for(int i=v;i>=1;--i) pushdown(sta[i]);
for(u=t[u].f;(fa=t[x].f)!=u;rotate(x))
if(t[fa].f!=u)
rotate(get(fa)==get(x)?fa:x);
}
void Access(int x) {
int y=0;
while(x) {
splay(x);
t[x].son-=t[y].size;
t[x].son+=t[rson].size;
rson=y,pushup(x),y=x,x=t[x].f;
}
}
void makeroot(int x) {
Access(x),splay(x),mark(x);
}
int findroot(int x) {
int u;
Access(x),splay(x);
while(x) {
pushdown(x);
u=x,x=lson;
}
return u;
}
void split(int x,int y) {
makeroot(x),Access(y),splay(y);
}
void link(int x,int y) {
makeroot(x), makeroot(y),t[x].f=y, t[y].son+=t[x].size,pushup(y);
}
void cut(int x,int y) {
makeroot(x),Access(y),splay(y);
t[y].ch[0]=t[x].f=0;
pushup(y);
}
int main() {
int i,j;
// setIO("input");
scanf("%d%d",&n,&m);
if(n%2==1) {
for(i=1;i<=m;++i) printf("-1\n");
return 0;
}
int cnt=n;
for(i=1;i<=m;++i) {
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
e[i]=Edge(u,v,c,i+n);
int x=findroot(u),y=findroot(v);
if(x!=y) {
int now=i+n;
makeroot(u),makeroot(v);
if(t[u].size%2==1&&t[v].size%2==1) cnt-=2;
t[now].val=c;
link(u,now),link(now,v);
q.push(Edge(u,v,c,now));
}
else {
split(u,v);
if(t[v].max>c) {
int cc=t[v].id,xx=e[cc-n].u,yy=e[cc-n].v,now=i+n;
cut(cc,xx),cut(cc,yy), t[now].val=c;
del[cc]=1;
link(u,now),link(now,v);
q.push(Edge(u,v,c,now));
}
}
if(cnt) printf("-1\n");
else {
while(1) {
while(!q.empty()&&del[q.top().id]) q.pop();
int xx=q.top().u,yy=q.top().v,cc=q.top().id,X,Y;
makeroot(cc);
Access(xx),splay(xx),X=t[xx].size-t[cc].size;
Access(yy),splay(yy),Y=t[yy].size-t[cc].size;
if(X%2==0&&Y%2==0)
cut(xx,cc),cut(yy,cc),q.pop();
else break;
}
printf("%d\n",q.top().c);
}
}
return 0;
}

  

CF603E Pastoral Oddities 优先队列+结论+LCT维护生成树的更多相关文章

  1. CF603E Pastoral Oddities

    CF603E Pastoral Oddities 度数不好处理.转化题意:不存在连通块为奇数时候就成功了(自底向上调整法证明) 暴力:从小到大排序加入.并查集维护.全局变量记录奇数连通块的个数 答案单 ...

  2. 洛谷4234最小差值生成树 (LCT维护生成树)

    这也是一道LCT维护生成树的题. 那么我们还是按照套路,先对边进行排序,然后顺次加入. 不过和别的题有所不同的是: 在本题中,我们需要保证LCT中正好有\(n-1\)条边的时候,才能更新\(ans\) ...

  3. Vijos1865 NOI2014 魔法森林 LCT维护生成树

    基本思路: 首先按照weightA升序排序,然后依次在图中加边,并维护起点到终点路径上weightB的最大值 如果加边过程中生成了环,则删除环中weightB最大的边 由于是无向图,点之间没有拓扑序, ...

  4. 【CF603E】Pastoral Oddities cdq分治+并查集

    [CF603E]Pastoral Oddities 题意:有n个点,依次加入m条边权为$l_i$的无向边,每次加入后询问:当前图是否存在一个生成子图,满足所有点的度数都是奇数.如果有,输出这个生成子图 ...

  5. LOJ 121 「离线可过」动态图连通性——LCT维护删除时间最大生成树 / 线段树分治

    题目:https://loj.ac/problem/121 离线,LCT维护删除时间最大生成树即可.注意没有被删的边的删除时间是 m+1 . 回收删掉的边的节点的话,空间就可以只开 n*2 了. #i ...

  6. bzoj 4736: 温暖会指引我们前行 (LCT 维护最大生成树)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4736 题面: 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出 ...

  7. BZOJ3514 Codechef MARCH14 GERALD07加强版 LCT维护最大生成树 主席树

    题面 考虑没有询问,直接给你一个图问联通块怎么做. 并查集是吧. 现在想要动态地做,那么应该要用LCT. 考虑新加进来一条边,想要让它能够减少一个联通块的条件就是现在边的两个端点还没有联通. 如果联通 ...

  8. Codeforces603E - Pastoral Oddities

    Portal Description 初始时有\(n(n\leq10^5)\)个孤立的点,依次向图中加入\(m(m\leq3\times10^5)\)条带权无向边.使得图中每个点的度数均为奇数的边集是 ...

  9. Codeforces 603E Pastoral Oddities

    传送门:http://codeforces.com/problemset/problem/603/E [题目大意] 给出$n$个点,$m$个操作,每个操作加入一条$(u, v)$长度为$l$的边. 对 ...

随机推荐

  1. RS232与RS485的功能与区别!

    转载于:http://blog.csdn.net/kevinhg/article/details/7367144 RS232接口是1970年由美国电子工业协会(EIA)联合贝尔系统.调制解调器厂家及计 ...

  2. 什么是PWA

    什么是PWA:https://www.jianshu.com/p/299c9c720e56 2019前端必会黑科技之PWA:https://www.jianshu.com/p/098af61bbe04 ...

  3. win10自带虚拟机的使用(Hyper-v)

    昨天刚发现的觉得特别好用,故推荐一下,跟VM虚拟机的使用方法是一样的 1.点击开始菜单中的<设置>图标,进入设置页码 2.点击<应用>图标,进入应用页码,并找到程序和功能 3. ...

  4. liunx忘记用户密码

    1.vim /etc/my.cnf [mysqld] skip-grant-tables ##追加此行,跳过权限表, 2.重启mysql systemctl restart mysqld 3.mysq ...

  5. the Percentage Layout of Android (安卓的百分比布局)

    不用wrap_content.match_parent来指定 控件的大小, 1.在app/bulid.gradle文件的dependencies中添加 compile 'com.android.sup ...

  6. mybatis查询返回的对象不为null,但是属性值为null

    返回的对象不为null,但是属性值为null 代码如下: <resultMap id="BaseResultMap" type="com.trhui.ebook.d ...

  7. react 在新窗口 打开页面

    遇到这个需求 首先通过 Link a去尝试直接跳转.发现2个问题 1.Link跳转 会自动进行登录校验,我设想是路由没有匹配到,去验证后大致排除了. 因为这个链接 直接粘贴到浏览器 是可以访问到的. ...

  8. kubeDNS workflow(service registration and discovery)

    Service discovery In k8s, we usually will more than make an application instance, and also the corre ...

  9. Django 数据库模块 单独使用

    pip install django pip install psycopg2 pip install mysqlclient Entity.py from django.db import mode ...

  10. linux chattr:配置文件隐藏属性;lsattr:显示文件属性

    1    chattr [+-=][ASadistu] 文件或目录名称 选项与参数: + :在原有参数设定基础上,追加参数.- :在原有参数设定基础上,移除参数.= :更新为指定参数设定.A:文件或目 ...