首先,一个神奇的结论:
一个合法的方案存在的条件是每一个联通块的节点数都是偶数个的.
这个可以用数学归纳法简单证一证.
证出这个后,我们只需动态加入每一个边,并查看一下有哪些边能够被删除(删掉后联通块依然合法).
对于维护加边,删边,我们用动态树.
对于枚举哪些边可以被删,我们可以用堆/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. Linux动态链接之GOT与PLT

    转载于:http://www.cnblogs.com/xingyun/archive/2011/12/10/2283149.html   我们知道函数名就是一个内存地址,这个地址指向函数的入口.调用函 ...

  2. oracle数据库表恢复到特定时间点

    某一张表被应用软件里误操作把数据都清空了,现在想恢复到清空之间,比如2013年8月13日14点以前,应该怎样操作? 通过这个问题可以引发一系列的知识点串联. 1.如果开启闪回可以使用闪回表. 怎样查看 ...

  3. SVN随笔记录(二)

    二.TortoiseSVN操作 1.下载,安装,过程中需要勾选x ,目的是为了后期绑定idea 2.如果点击后出现一系列的找不到目标文件提示,重启电脑 3.重启后,绑定仓库路径 4.一般情况输入账号密 ...

  4. 【2017.12.02】C组比赛总结

    这次考得不怎么样,只有200分! T1:读书 这题水水水! 这题就是一道循环题嘛! 直接一边循环一边做就好了! T2:恐怖分子 这题我是直接暴力的. 这题就是求至少用多少条经过(x0,y0)的不同直线 ...

  5. CSP 命令行选项(201403-3)

    问题描述 请你写一个命令行分析程序,用以分析给定的命令行里包含哪些选项.每个命令行由若干个字符串组成,它们之间恰好由一个空格分隔.这些字符串中的第一个为该命令行工具的名字,由小写字母组成,你的程序不用 ...

  6. Java switch case 语句

    switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支. 语法 switch(expression){ case value : //语句 break; //可选 ca ...

  7. Hive 教程(九)-python with hive

    本文介绍用 python 远程连接 hive,此时需要 hive 启动 hiveserver2 服务 windows 下报如下错误 thrift.transport.TTransport.TTrans ...

  8. 进程之multiprocessing模块代码篇

    这里再把之前的内容总结和补充一下: 并发和并行: 你在干坏事,来了一个电话,干完坏事再去接电话,说明你既不是并发也不是并行. 你在干坏事,来了一个电话,你接完电话接着干坏事,说明你支持并发 你在干坏事 ...

  9. [Next] 服务端渲染知识补充

    渲染 渲染:就是将数据和模版组装成 html 客户端渲染 客户端渲染模式下,服务端把渲染的静态文件给到客户端,客户端拿到服务端发送过来的文件自己跑一遍 js,根据 JS 运行结果,生成相应 DOM,然 ...

  10. 简单搭建http服务器-HttpListener使用

    使用HTTPListener可以简单搭建一个Http服务器,对于本地使用很是方面,想起之前使用了WebSocket来与本地网页通讯的例子,也是可以改为使用HTTPListener来做的.看下HTTPL ...