传送门

题意简述:

给你一棵nnn个黑白点的树,初始全是黑点。

现在支持给一个点换颜色或者求整颗树中离某个点最近的白点跟这个点的距离。


思路:

考虑链分治维护答案,每个链顶用一个堆来维护答案,然后对于每条重链开一棵线段树维护子树里所有白点到线段树最左/右端点的最短距离。

然后瞎更新查询即可。

代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(((ans<<2)+ans)<<1)+(ch^48),ch=getchar();
	return ans;
}
const int N=1e5+5,inf=1e8;
bool col[N];
struct deletable_priority_queue{
	priority_queue<int,vector<int>,greater<int> >a,b;
	inline void push(const int&x){a.push(x);}
	inline void del(const int&x){b.push(x);}
	inline int top(){while(b.size()&&a.top()==b.top())a.pop(),b.pop();return a.top();}
	inline int size(){return a.size()-b.size();}
	inline void f(int x,int&a,int&b){
		a=b=inf;
		if(col[x])a=b=0;
		if(size())a=b=min(a,top());
	}
}h[N];
int siz[N],hson[N],top[N],num[N],bot[N],pred[N],fa[N],n,m,tot=0,dep[N];
vector<int>e[N];
void dfs1(int p){
	siz[p]=1;
	for(ri i=0,v;i<e[p].size();++i){
		if((v=e[p][i])==fa[p])continue;
		fa[v]=p,dep[v]=dep[p]+1,dfs1(v),siz[p]+=siz[v];
		if(siz[v]>siz[hson[p]])hson[p]=v;
	}
}
void dfs2(int p,int tp){
	top[p]=tp,bot[tp]=p,pred[num[p]=++tot]=p;
	if(!hson[p])return;
	dfs2(hson[p],tp);
	for(ri i=0,v;i<e[p].size();++i){
		if((v=e[p][i])==hson[p]||v==fa[p])continue;
		dfs2(v,v);
	}
}
namespace SGT{
	#define lc (p<<1)
	#define rc (p<<1|1)
	#define mid (T[p].l+T[p].r>>1)
	struct Node{int l,r,ls,rs,sum;}T[N<<2];
	inline Node operator+(const Node&a,const Node&b){
		Node ret;
		ret.l=a.l,ret.r=b.r;
		ret.sum=a.sum+1+b.sum;
		ret.ls=min(a.ls,a.sum+1+b.ls);
		ret.rs=min(b.rs,b.sum+1+a.rs);
		return ret;
	}
	inline void Set(int p){
		int k=pred[T[p].l];
		T[p].sum=0,h[k].f(k,T[p].ls,T[p].rs);
	}
	inline void pushup(int p){T[p]=T[lc]+T[rc];}
	inline void build(int p,int l,int r){
		T[p].l=l,T[p].r=r,T[p].ls=T[p].rs=inf,T[p].sum=0;
		if(l==r)return;
		build(lc,l,mid),build(rc,mid+1,r);
	}
	inline void update(int p,int k){
		if(T[p].l==T[p].r)return Set(p);
		update(k<=mid?lc:rc,k),pushup(p);
	}
	inline Node query(int p,int ql,int qr){
		if(ql<=T[p].l&&T[p].r<=qr)return T[p];
		if(qr<=mid)return query(lc,ql,qr);
		if(ql>mid)return query(rc,ql,qr);
		return query(lc,ql,qr)+query(rc,ql,qr);
	}
	#undef lc
	#undef rc
	#undef mid
}
int dfs3(int tp){
	for(ri p=tp;p;p=hson[p]){
		for(ri i=0,v;i<e[p].size();++i){
			if((v=e[p][i])==fa[p]||v==hson[p])continue;
			h[p].push(dfs3(v)+1);
		}
		SGT::update(1,num[p]);
	}
	return SGT::query(1,num[tp],num[bot[tp]]).ls;
}
inline void update(int p){
	while(p){
		int ft=fa[top[p]],tp=top[p];
		if(ft){
			SGT::Node tmp=SGT::query(1,num[tp],num[bot[tp]]);
			h[ft].del(tmp.ls+1);
		}
		SGT::update(1,num[p]);
		if(ft){
			SGT::Node tmp=SGT::query(1,num[tp],num[bot[tp]]);
			h[ft].push(tmp.ls+1);
		}
		p=ft;
	}
}
inline int query(int x){
	int p=x,ret=SGT::query(1,num[x],num[bot[top[x]]]).ls;
	while(p){
		int ft=fa[top[p]],tp=top[p];
		ret=min(ret,SGT::query(1,num[tp],num[p]).rs+dep[x]-dep[p]);
		ret=min(ret,SGT::query(1,num[p],num[bot[tp]]).ls+dep[x]-dep[p]);
		p=ft;
	}
	return ret;
}
int main(){
	n=read();
	for(ri i=1,u,v;i<n;++i)u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
	dfs1(1),dfs2(1,1),SGT::build(1,1,n),dfs3(1);
	for(ri all=0,v,tt=read();tt;--tt){
		if(read()){
			v=read();
			if(!all)puts("-1");
			else if(col[v])puts("0");
			else cout<<query(v)<<'\n';
		}
		else{
			v=read();
			col[v]^=1;
			if(col[v])++all;
			else --all;
			update(v);
		}
	}
	return 0;
}

2019.02.17 spoj Query on a tree V(链分治)的更多相关文章

  1. 2019.02.17 spoj Query on a tree VII(链分治)

    传送门 跟QTREE6QTREE6QTREE6神似,改成了求连通块里的最大值. 于是我们对每条链开一个heapheapheap维护一下即可. MDMDMD终于1A1A1A链分治了. 代码: #incl ...

  2. 2019.02.17 spoj Query on a tree VI(链分治)

    传送门 题意简述:给你一棵nnn个黑白点的树,支持改一个点的颜色,询问跟某个点颜色相同的连通块大小. 思路: 还是链分治 233 记fi,0/1f_{i,0/1}fi,0/1​表示iii的所有颜色为0 ...

  3. 2019.02.16 spoj Query on a tree IV(链分治)

    传送门 题意简述: 捉迷藏强化版(带有边权,可以为负数) 思路:好吧这次我们不用点分树,我们用听起来更屌的链分治. 直接把树剖成若干条重链,这样保证从任意一个点跳到根节点是不会跳超过logloglog ...

  4. SPOJ Query on a tree 树链剖分 水题

    You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...

  5. SPOJ Query on a tree V

    You are given a tree (an acyclic undirected connected graph) with N nodes. The tree nodes are number ...

  6. SPOJ - QTREE5 Query on a tree V 边分治

    题目传送门 题意:给你一棵树, 然后树上的点都有颜色,且原来为黑,现在有2个操作,1 改变某个点的颜色, 2 询问树上的白点到u点的最短距离是多少. 题解: 这里用的还是边分治的方法. 把所有东西都抠 ...

  7. QTREE5 - Query on a tree V——LCT

    QTREE5 - Query on a tree V 动态点分治和动态边分治用Qtree4的做法即可. LCT: 换根后,求子树最浅的白点深度. 但是也可以不换根.类似平常换根的往上g,往下f的拼凑 ...

  8. spoj QTREE - Query on a tree(树链剖分+线段树单点更新,区间查询)

    传送门:Problem QTREE https://www.cnblogs.com/violet-acmer/p/9711441.html 题解: 树链剖分的模板题,看代码比看文字解析理解来的快~~~ ...

  9. SPOJ QTREE Query on a tree 树链剖分+线段树

    题目链接:http://www.spoj.com/problems/QTREE/en/ QTREE - Query on a tree #tree You are given a tree (an a ...

随机推荐

  1. NFS服务配置

    FS服务会经常用于在网络上共享存储. 比如有3台机子A,B,C;他们都需要访问同一个目录,使用NFS, 只需要把图片都放在A上,然后A共享给B和C即可. 访问B和C时,是通过网络的方式访问A上的哪个目 ...

  2. 刘志梅 201771010115 《面向对象程序设计(java)》 第七周学习总结

    实验七 继承附加实验 实验时间 2018-10-11 1.实验目的与要求 (1)进一步理解4个成员访问权限修饰符的用途: 即将类中的域标记为private,而方法标记为public.任何声明为priv ...

  3. winCVS 使用的一个小要点

    对于版本管理软件CVS,可以在Linux中使用命令来管理. 但是 在windows 界面下,也可以使用 winCVS 工具来管理. 现在 讲一下 如何 在 winCVS 登陆 CVS 帐号 和 密码: ...

  4. 实战ELK(4)Metricbeat 轻量型指标采集器

    一.介绍 用于从系统和服务收集指标.从 CPU 到内存,从 Redis 到 Nginx,Metricbeat 能够以一种轻量型的方式,输送各种系统和服务统计数据. 1.系统级监控,更简洁(轻量型指标采 ...

  5. 浅读《视觉SLAM十四讲:从理论到实践》--操作1--初识SLAM

    下载<视觉SLAM十四讲:从理论到实践>源码:https://github.com/gaoxiang12/slambook 第二讲:初识SLAM 2.4.2 Hello SLAM(书本P2 ...

  6. 5.HTML+CSS制作一颗流星

    效果地址:https://codepen.io/flyingliao/pen/pBzKbZ HTML code: <div class="sky"> <span& ...

  7. mac 安装软件

    一.安装spark 1.官网下载最新tar文件 2.解压 3.安装java开发环境 3.1.安装下载java 8  https://www.oracle.com/technetwork/java/ja ...

  8. python基础之从认识python到python的使用

    python的历史: python的创始人是吉多·范罗苏姆(Guido van Rossum),人称“龟叔”,1989年圣诞节期间,Guido开始写Python语言的编译器.他希望这个叫做Python ...

  9. Centos创建用户

    1.创建用户: adduser fish 2.用户设置密码: passwd linuxidc 3.创建文件夹: mkdir fish 4.删除文件夹 rm -rf fish 5.文件夹重命名: mv ...

  10. leetcode72

    class Solution { private: ][]; public: int minDistance(string word1, string word2) { int len1 = word ...