BZOJ 3319: 黑白树 并查集 + 离线 + 思维
Description
Input
Output
我们知道,并查集是向上合并的
如果正着做,每一次将一条路径染黑,会导致很多白点的祖先改变,而且是向下变
向下变就十分麻烦,非常不好做
不妨逆着操作,记录每一个节点变黑的最早时间,将操作逆着进行
可以先将整棵树全部染黑,逆着逐渐染白,那么每个白点的祖先只会更向上,向上合并
比如当前要将点 $x$ 染白,那么 $x$ 子树中的白点在改动前并查集指向的祖先都是 $x$
在改动后 $x$ 的祖先会向上合并,而 $x$ 子树中的白点在并查集查祖先时查到 $x$ 的话会顺着 $x$ 向上合并到的祖先继续向上查询
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#define setIO(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 1002002
using namespace std;
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd() {int x=0; char c=nc(); while(c<48) c=nc(); while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x;}
vector<int>G[maxn];
stack<int>S;
int n,m,edges;
int tm[maxn],hd[maxn<<1],to[maxn<<1],nex[maxn<<1];
int siz[maxn],top[maxn],fa[maxn],dep[maxn],son[maxn];
int idx[maxn<<1],id[maxn<<1];
inline void addedge(int u,int v,int c) {
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v, id[edges]=c;
}
void dfs1(int u,int ff) {
dep[u]=dep[ff]+1,siz[u]=1,fa[u]=ff;
for(int i=hd[u];i;i=nex[i]) {
int v=to[i];
if(v==ff) continue;
idx[v]=id[i], dfs1(v,u), siz[u]+=siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs2(int u,int tp) {
top[u]=tp;
if(son[u]) dfs2(son[u], tp);
for(int i=hd[u];i;i=nex[i]) {
int v=to[i];
if(v==fa[u] || v==son[u]) continue;
dfs2(v,v);
}
}
inline int LCA(int x,int y) {
while(top[x]^top[y]) {
dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
}
return dep[x]<dep[y]?x:y;
}
struct Opt {
int opt,x,y;
}op[maxn];
struct Union {
int p[maxn];
inline void init() {
for(int i=0;i<maxn;++i) p[i]=i;
}
int find(int x) {
return p[x]==x?x:p[x]=find(p[x]);
}
}black,white;
inline void mark(int u,int lca,int cur) {
u=tm[u]?black.find(u):u;
while(dep[u]>dep[lca]) {
tm[u]=cur;
if(!tm[fa[u]]) {
black.p[u]=fa[u];
u=fa[u];
}
else {
int y=black.find(fa[u]);
black.p[u]=y;
u=y;
}
}
}
inline void update(int u,int v,int cur) {
int lca=LCA(u,v);
mark(u,lca,cur), mark(v,lca,cur);
}
inline void change(int u) {
white.p[u]=white.find(fa[u]);
}
int main() {
// setIO("input");
scanf("%d%d",&n,&m);
for(int i=1;i<n;++i) {
int u,v;
u=rd(),v=rd();
addedge(u,v,i),addedge(v,u,i);
}
dfs1(1,0), dfs2(1,1), black.init();
for(int i=1;i<=m;++i) {
op[i].opt=rd();
if(op[i].opt==1) op[i].x=rd();
if(op[i].opt==2) op[i].x=rd(), op[i].y=rd(), update(op[i].x,op[i].y,i);
}
white.init();
for(int i=2;i<=n;++i) G[tm[i]==0?m+1:tm[i]].push_back(i);
m+=(G[m+1].size()>1);
for(int i=m;i>=1;--i) {
if(G[i].size()) {
for(int j=0;j<G[i].size();++j) change(G[i][j]);
}else if(op[i].opt==1) {
S.push(white.find(op[i].x));
}
}
while(!S.empty()) {
printf("%d\n",idx[S.top()]); S.pop();
}
return 0;
}
BZOJ 3319: 黑白树 并查集 + 离线 + 思维的更多相关文章
- BZOJ 3319 黑白树 并查集+线段树
这这这这这这什么毒瘤题!!!!!!!!!!!!!!!!!!!!!!!!!!!! 卡LCT(优秀的LCT由于是均摊本身就带着2,3的常数在,而且这道题对于LCT标记十分难维护,又得乘上4,5然后就炸了) ...
- poj 2528 Mayor's posters 线段树 || 并查集 离线处理
题目链接 题意 用不同颜色的线段覆盖数轴,问最终数轴上有多少种颜色? 注:只有最上面的线段能够被看到:即,如果有一条线段被其他的线段给完全覆盖住,则这个颜色是看不到的. 法一:线段树 按题意按顺序模拟 ...
- [BZOJ 3319] 黑白树
3319: 黑白树 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 557 Solved: 194[Submit][Status][Discuss] ...
- BZOJ 3319: 黑白树 树+并查集+未调完+神题
Code: #include<bits/stdc++.h> #define maxn 1000003 using namespace std; char *p1,*p2,buf[10000 ...
- 【BZOJ3319】黑白树 并查集
[BZOJ3319]黑白树 Description 给定一棵树,边的颜色为黑或白,初始时全部为白色.维护两个操作:1.查询u到根路径上的第一条黑色边的标号.2.将u到v 路径上的所有边的颜色设为 ...
- BZOJ 3211 线段树+并查集
思路: 我们很容易发现 一个数开根号 开几(很小)次 就到了1 1 再怎么开 都是1 由于这个性质 我们就可以用并查集 了 //By SiriusRen #include <cmath> ...
- [HDU3710] Battle Over Cities [树链剖分+线段树+并查集+kruskal+思维]
题面 一句话题意: 给定一张 N 个点, M 条边的无向连通图, 每条边上有边权 w . 求删去任意一个点后的最小生成树的边权之和. 思路 首先肯定要$kruskal$一下 考虑$MST$里面去掉一个 ...
- 【BZOJ】3319: 黑白树(并查集+特殊的技巧/-树链剖分+线段树)
http://www.lydsy.com/JudgeOnline/problem.php?id=3319 以为是模板题就复习了下hld............................. 然后n ...
- 【BZOJ】3319: 黑白树
http://www.lydsy.com/JudgeOnline/problem.php?id=3319 题意:给一棵n节点的树(n<=1e6),m个操作(m<=1e6),每次操作有两种: ...
随机推荐
- JPA-style positional param was not an integral ordinal 异常
JPA-style positional param was not an integral ordinal 多是sql之间的空格问题,或者sql拼接问题. 字符串与字符串直接相加要加空格
- Spark启动流程(Standalone)- master源码
Master源码 package org.apache.spark.deploy.master //伴生类 private[deploy] class Master( override val rpc ...
- RabbitMq学习4-发布/订阅(Publish/Subscribe)
一.发布/订阅 分发一个消息给多个消费者(consumers).这种模式被称为“发布/订阅”. 为了描述这种模式,我们将会构建一个简单的日志系统.它包括两个程序——第一个程序负责发送日志消息,第二个程 ...
- P4290 [HAOI2008]玩具取名
传送门 $dp$ 设 $f[i][j][k]$ 表示初始为 $k$ 时,能否得到 $[i,j]$ 这一段子串 设 $pd[i][j][k]$ 表示长度为二的字符串 $ij$ 能否由 $k$ 得到 然后 ...
- luogu P5340 [TJOI2019]大中锋的游乐场
传送门 要求经过路径汉堡的点和可乐的点个数之差绝对值\(\le k\),所以可以考虑dp,\(f_{i,j}\)表示到点\(i\),汉堡的点个数减可乐的点的个数为\(j\)的最短距离,注意一下负下标处 ...
- Vue双向绑定的实现原理及简单实现
vue数据双向绑定原理 vue数据双向绑定是通过(数据劫持)+(发布者-订阅者模式)的方式来实现的,而所谓的数据劫持就是通过Object.defineProperty() 来实现的,所谓的Obje ...
- Bootstrap table 实现树形表格,实现联动选中,联动取消
公司最近有需求要做树形式table.因为是前后端不分离项目,且之前已经引入了bootstrap table插件,现把实现方式分享一下: <!DOCTYPE HTML> <html l ...
- 基于maven的javaweb项目模块化开发
转自:https://my.oschina.net/kingfire/blog/273381 基于maven的javaweb项目模块化开发 引言 考虑团队拥有多个类似项目的情况,比如一些功能差异不大的 ...
- Docker其他操作:查看内部细节、IP、删除容器
1.查看容器内部细节 查看容器运行内部细节,比如可看容器的IP docker inspect mycentos2 2.查看容器IP地址 直接显示IP地址 docker inspect --format ...
- 雷电模拟器 v3.71绿色版
目录 1. 按 2. 介绍 3. 下载地址 1. 按 安卓模拟器目前的市场基本上稳定了,逍遥.夜神.雷电,用的人都很多,网易mumu从阴阳师时代就被大家熟知,腾讯手游助手也是随着吃鸡游戏而火,这两个模 ...