2019.02.17 spoj Query on a tree V(链分治)
传送门
题意简述:
给你一棵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(链分治)的更多相关文章
- 2019.02.17 spoj Query on a tree VII(链分治)
传送门 跟QTREE6QTREE6QTREE6神似,改成了求连通块里的最大值. 于是我们对每条链开一个heapheapheap维护一下即可. MDMDMD终于1A1A1A链分治了. 代码: #incl ...
- 2019.02.17 spoj Query on a tree VI(链分治)
传送门 题意简述:给你一棵nnn个黑白点的树,支持改一个点的颜色,询问跟某个点颜色相同的连通块大小. 思路: 还是链分治 233 记fi,0/1f_{i,0/1}fi,0/1表示iii的所有颜色为0 ...
- 2019.02.16 spoj Query on a tree IV(链分治)
传送门 题意简述: 捉迷藏强化版(带有边权,可以为负数) 思路:好吧这次我们不用点分树,我们用听起来更屌的链分治. 直接把树剖成若干条重链,这样保证从任意一个点跳到根节点是不会跳超过logloglog ...
- SPOJ Query on a tree 树链剖分 水题
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...
- SPOJ Query on a tree V
You are given a tree (an acyclic undirected connected graph) with N nodes. The tree nodes are number ...
- SPOJ - QTREE5 Query on a tree V 边分治
题目传送门 题意:给你一棵树, 然后树上的点都有颜色,且原来为黑,现在有2个操作,1 改变某个点的颜色, 2 询问树上的白点到u点的最短距离是多少. 题解: 这里用的还是边分治的方法. 把所有东西都抠 ...
- QTREE5 - Query on a tree V——LCT
QTREE5 - Query on a tree V 动态点分治和动态边分治用Qtree4的做法即可. LCT: 换根后,求子树最浅的白点深度. 但是也可以不换根.类似平常换根的往上g,往下f的拼凑 ...
- spoj QTREE - Query on a tree(树链剖分+线段树单点更新,区间查询)
传送门:Problem QTREE https://www.cnblogs.com/violet-acmer/p/9711441.html 题解: 树链剖分的模板题,看代码比看文字解析理解来的快~~~ ...
- 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 ...
随机推荐
- 经典算法二分查找循环实现Java版
二分查找 定义 二分查找(Binary Search)又称折半查找,它是一种效率较高的查找方法. 要求 (1)必须采用顺序存储结构 (2)必须按关键字大小有序排列 查找思路 首先将给定值K,与表中中间 ...
- iOS ReactiveCocoa的使用
一.ReactiveCocoa简介 reactiveCocoa简称RAC,它是一个三方框架,很多人把它叫做函数响应式编程框架,因为它具有函数式编程和响应式编程的特性. 由于该框架的编程思想,使得它具有 ...
- How to identify safari in Mac?
How to identify safari in Mac?in userAgent, find keywords below1) and: Macintosh, Mac OS X, AppleWeb ...
- Python全栈开发记录_第一篇(循环练习及杂碎的知识点)
Python全栈开发记录只为记录全栈开发学习过程中一些难和重要的知识点,还有问题及课后题目,以供自己和他人共同查看.(该篇代码行数大约:300行) 知识点1:优先级:not>and 短路原则:a ...
- [持续交付实践] pipeline使用:快速入门
什么是pipeline 先介绍下什么是Jenkins 2.0,Jenkins 2.0的精髓是Pipeline as Code,是帮助Jenkins实现CI到CD转变的重要角色.什么是Pipeline, ...
- linux环境下载和安装scala
Linux下安装Scala和Windows下安装类似,步骤如下: 1.首先访问下载链接:http://www.scala-lang.org/download/默认这里下载的是Windows版本,这时点 ...
- .NET项目中使用PostSharp
PostSharp是一种Aspect Oriented Programming 面向切面(或面向方面)的组件框架,适用在.NET开发中,本篇主要介绍Postsharp在.NET开发中的相关知识,以及一 ...
- git 提交小备注
总结: · git add -A 提交所有变化 · git add -u 提交被修改(modified)和被删除(deleted)文件,不包括新文件(new) · git add . 提交 ...
- layer.js 中弹框显示不全的问题
在使用 layer.js 做弹框的时候,遇到在浏览器缩小时,弹框显示不全的问题,如下: 这是不行的,因为我们有的时候想缩小浏览器视窗,但是一旦缩小到一定程度,就会把弹窗的关闭按钮遮住一部分,并且主体弹 ...
- 面试小结之Elasticsearch篇(转)
最近面试一些公司,被问到的关于Elasticsearch和搜索引擎相关的问题,以及自己总结的回答. Elasticsearch是如何实现Master选举的? Elasticsearch的选主是ZenD ...