https://zybuluo.com/ysner/note/1236834

题面

给出一棵边带权的节点数量为\(n\)的树,初始树上所有节点都是白色。有两种操作:

  • 改变节点\(x\)的颜色,即白变黑,黑变白
  • 询问树中最远的两个白色节点的距离,这两个白色节点可以重合(此时距离为\(0\))。

\(n\leq10^5,q\leq2*10^5\)

解析

打这道题的过程中,\(get\)了许多新姿势。

点分治经典问题。每次分治时找到每棵子树深度最大的一个白点,用最大的两个统计一下即可。

找最大和次大自然需要堆,且每个点都需要开两个。

第一个堆插入这个重心管辖的一坨树所有白点到分治树上这个点父亲的距离。

第二个堆插入所有点分治树上孩子的堆顶,这样我们就可以对于每个分治重心,找到分属两棵子树的深度最大的两个白点,即这个点堆的最大和次大值。

修改就只要再点分树上从自己的重心往根走,然后维护一下那些堆。

注意这些堆要可删除(即可以指定删除其中一个元素)。

原理是每个堆里设一个删除堆和插入堆,插入元素就插入插入堆,删除元素就插入删除堆。如要取堆顶,就把两堆同时弹到堆顶不相等即可,取插入堆堆顶即可。

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
#define re register
#define il inline
#define inf 1000000000
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=5e5+100;
struct Edge{int to,nxt,w;}e[N<<1];
struct dui
{
priority_queue<int>s,t;int sz;
il void pop(re int x){t.push(x);--sz;}
il void push(re int x){s.push(x);++sz;}
il void pre(){while(t.size()&&s.top()==t.top()) s.pop(),t.pop();}
il int top(){pre();return sz?s.top():-inf;}
il int len()
{
if(sz<2) return 0;
re int x=top();pop(x);
re int y=top();push(x);
return max(x+y,0);
}
il void del(re int x,re int k){k?pop(x):push(x);}
}a[N],b[N],ans;
int n,h[N],cnt,Q,d[N],dis[N],f[N],sz[N],mx,mn,Sz[N],top[N],son[N],root,Size,F[N],w[N],tot,s[N],tim;
bool vis[N];
il void add(re int u,re int v,re int w){e[++cnt]=(Edge){v,h[u],w};h[u]=cnt;}
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il void dfs1(re int u,re int fa)
{
d[u]=d[fa]+1;f[u]=fa;sz[u]=1;
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(v==fa) continue;
dis[v]=dis[u]+e[i].w;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[son[u]]<sz[v]) son[u]=v;
}
}
il void dfs2(re int u,re int up)
{
top[u]=up;
if(son[u]) dfs2(son[u],up);
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(v==f[u]||v==son[u]) continue;
dfs2(v,v);
}
}
il int lca(re int u,re int v)
{
while(top[u]^top[v])
{
if(d[top[u]]<d[top[v]]) swap(u,v);
u=f[top[u]];
}
return d[u]<d[v]?u:v;
}
il int Dis(re int u,re int v){return dis[u]+dis[v]-2*dis[lca(u,v)];}
il void Getrt(re int u,re int fa)
{
re int mx=0;Sz[u]=1;s[++tim]=u;
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(v==fa||vis[v]) continue;
Getrt(v,u);
Sz[u]+=Sz[v];
mx=max(mx,Sz[v]);
}
mx=max(mx,Size-Sz[u]);
if(mx<mn) mn=mx,root=u;
}
il int dfs(re int u,re int fa)
{
vis[u]=1;F[u]=fa;b[u].push(0);
if(F[u]) fp(i,1,tim) a[u].push(Dis(s[i],F[u]));
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(vis[v]) continue;
Size=Sz[v];mn=n;tim=0;
Getrt(v,u);
re int p=dfs(root,u);
b[u].push(a[p].top());
}
ans.push(b[u].len());
return u;
}
il void Modify(re int u,re int w)
{
re int l1=b[u].len(),l2,s1,s2;
b[u].del(0,w);l2=b[u].len();
if(l1^l2) ans.pop(l1),ans.push(l2);
for(re int i=u;F[i];i=F[i])
{
s1=a[i].top();
a[i].del(Dis(u,F[i]),w);
s2=a[i].top();
if(s1==s2) continue;
l1=b[F[i]].len();
if(s1!=-inf) b[F[i]].pop(s1);if(s2!=-inf) b[F[i]].push(s2);
l2=b[F[i]].len();
if(l1^l2) ans.pop(l1),ans.push(l2);
}
}
int main()
{
memset(h,-1,sizeof(h));
tot=n=gi();
fp(i,1,n-1)
{
re int u=gi(),v=gi(),w=gi();
add(u,v,w);add(v,u,w);
}
dfs1(1,0);dfs2(1,1);
Size=mn=n;Getrt(1,0);
dfs(root,0);
fp(i,1,n) w[i]=1;
Q=gi();
while(Q--)
{
re char op='0';while(op!='A'&&op!='C') op=getchar();
if(op=='A')
{
tot?printf("%d\n",tot==1?0:ans.top()):puts("They have disappeared.");
}
if(op=='C')
{
re int u=gi();tot+=(w[u]?-1:1);
Modify(u,w[u]);w[u]^=1;
}
}
return 0;
}

qtree4的更多相关文章

  1. 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)

    题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...

  2. luogu P4115 Qtree4

    题目链接 luogu P4115 Qtree4 题解 动态点分治,和上一题一样.同样三个堆.就是带权,用边权替换深度就好 为什么要单独写这个题解呢,因为我卡常卡了一天....据说树剖比rmq快? 在第 ...

  3. SPOJ2666 QTREE4

    我是萌萌的传送门 我是另一个萌萌的传送门 一道树分治……简直恶心死了……我在调代码的时候只想说:我*************************************************…… ...

  4. 洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV

    意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次.因此原树上任意一个节点都会出现在点分树上,且是恰好一次 https://www.cnblogs.com/zzq ...

  5. SPOJ QTREE4 lct

    题目链接 这个题已经处于花式tle了,改版后的spoj更慢了.. tle的话就多交几把... #include <iostream> #include <fstream> #i ...

  6. 洛谷 4115 Qtree4——链分治

    题目:https://www.luogu.org/problemnew/show/P4115 论文:https://wenku.baidu.com/view/1bc2e4ea172ded630b1cb ...

  7. Qtree4——动态点分治

    题目描述 给出一棵边带权的节点数量为n的树,初始树上所有节点都是白色.有两种操作: C x,改变节点x的颜色,即白变黑,黑变白 A,询问树中最远的两个白色节点的距离,这两个白色节点可以重合(此时距离为 ...

  8. luoguP4115 QTREE4 链分治

    具体看$qzc$论文吧......陈年老物了...... 主要注意每个链头一棵线段树而不是一棵全局线段树 修改操作写完就是正确的,反而是初始化调了好一会...... 跑的还是很快的,有些地方没优化常数 ...

  9. SP2666 QTREE4 - Query on a tree IV(LCT)

    题意翻译 你被给定一棵n个点的带边权的树(边权可以为负),点从1到n编号.每个点可能有两种颜色:黑或白.我们定义dist(a,b)为点a至点b路径上的权值之和. 一开始所有的点都是白色的. 要求作以下 ...

  10. SPOJ QTREE4 SPOJ Query on a tree IV

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

随机推荐

  1. 16Oracle Database 系统权限和对象权限

    Oracle Database 系统权限和对象权限 Oracle中的系统权限和对象权限 DCL 数据控制语言 -- 查看对象的权限 grant / revoke 查看登录用户 Show user 查看 ...

  2. spring aop 内部调用问题解决

    方法1: 基于 proxy 的 spring aop 带来的内部调用问题可以使用 AopContext.currentProxy() 强转为当前的再调用就可以解决了 例如: 错误用法:public A ...

  3. Java基础——从数组到集合之间关键字的区别!!!!

    1.&& 和 &区别和联系: 相同点 : 结果是一样的.       不同点 :如果使用双&号判断,如果说条件一为false,不会判断条件二,但是单&号会继续判 ...

  4. 洛谷——P1972 [SDOI2009]HH的项链(线段树)

    P1972 [SDOI2009]HH的项链 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不断地收集新的 ...

  5. SQLAlchemy-Utils

    由于sqlalchemy中没有提供choice方法,所以借助SQLAlchemy-Utils组件提供的choice方法. 安装: pip3 install sqlalchemy_utils 示例: f ...

  6. python 读取指定文件信息并拼接

    python 读取指定文本并拼接成指定的格式 # -*- coding: utf-8 -*- import os def getHelloWorld(path, fileName): "&q ...

  7. 【08】AngularJS XMLHttpRequest

    AngularJS XMLHttpRequest $http 是 AngularJS 中的一个核心服务,用于读取远程服务器的数据. 读取 JSON 文件 以下是存储在web服务器上的 JSON 文件: ...

  8. Android第三方开源SwitchButton

    Android第三方开源SwitchButton Android SwitchButton是github上的一个第三方开源项目,其项目主页是:https://github.com/kyleduo/Sw ...

  9. poj3352

    Road Construction Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 7980 Accepted: 4014 Des ...

  10. 超级钢琴(codevs 2934)

    题目描述 Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音 ...