两次LCT的Access操作就可以求LCA啦

题目

给出一棵树,支持单点反色和查询全局最远白点


分析(点分树)

点分树的做法就是考虑点分树上的父亲把子树分成若干个部分,

那么所谓的白点直径可以把子树的最长链拼接起来

那么开三个可删堆,一个维护点分子树到父亲的距离,

一个维护父亲的答案,取第一个堆的最大值以保证其中每个值所属子树各不相同,

一个维护全局答案也就是直接用第二个堆的最大值和次大值合并起来,注意舍弃不必要的操作减小常数


代码

#include <cstdio>
#include <cctype>
#include <queue>
#include <algorithm>
#define rr register
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin)),p1==p2?EOF:*p1++)
using namespace std;
const char S[22]={84,104,101,121,32,104,97,118,101,32,100,105,115,97,112,112,101,97,114,101,100,'.'};
const int N=100011; bool v[N]; struct node{int y,w,next;}e[N<<1];
int big[N],siz[N],SIZ,dfn[N],Siz[N],fat[N],root,as[N],tot;
char buf[1<<23],puf[1<<23],*p1,*p2; int nowp=-1;
int dep[N],et=1,two[18],lg[N<<1],f[N<<1][18],n,m,cnt,dis[N];
inline signed iut(){
rr int ans=0,f=1; rr char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans*f;
}
inline void Flush(){fwrite(puf,1,nowp+1,stdout),nowp=-1;}
inline void Putchar(char x){
if (nowp==(1<<23)) Flush();
puf[++nowp]=x;
}
inline void print(int ans){
rr char dig[21]; rr int len=-1;
do{
dig[++len]=ans%10+48,ans/=10;
}while (ans);
while (len>=0) Putchar(dig[len--]);
}
inline void Max(int &a,int b){a=a>b?a:b;}
inline void Min(int &a,int b){a=a<b?a:b;}
inline signed Get_Min(int x,int y){return dep[x]<dep[y]?x:y;}
inline signed lca(int x,int y){
if (x>y) x^=y,y^=x,x^=y; rr int z=lg[y-x+1];
return Get_Min(f[x][z],f[y-two[z]+1][z]);
}
inline signed Dis(int x,int y){
rr int LCA=lca(dfn[x],dfn[y]);
return dis[x]+dis[y]-2*dis[LCA];
}
inline void dfs(int x,int fa){
siz[x]=1,big[x]=0;
for (rr int i=as[x];i;i=e[i].next)
if (e[i].y!=fa&&!v[e[i].y]){
dfs(e[i].y,x);
siz[x]+=siz[e[i].y];
Max(big[x],siz[e[i].y]);
}
Max(big[x],SIZ-siz[x]);
if (big[x]<=big[root]) root=x;
}
inline void dp(int x){
v[x]=1,Siz[x]=big[0];
for (rr int i=as[x];i;i=e[i].next)
if (!v[e[i].y]){
big[0]=SIZ=siz[e[i].y];
dfs(e[i].y,root=0),
fat[root]=x,dp(root);
}
}
inline void Dfs(int x,int fa){
f[dfn[x]=++tot][0]=x,dep[x]=dep[fa]+1;
for (rr int i=as[x];i;i=e[i].next)
if (e[i].y!=fa){
dis[e[i].y]=dis[x]+e[i].w;
Dfs(e[i].y,x),f[++tot][0]=x;
}
}
struct Heap{
priority_queue<int>q0,q1;
inline signed Size(){return q0.size()-q1.size();}
inline void Push(int x){q0.push(x);}
inline void Pop(int x){q1.push(x);}
inline signed Top(){
while (!q1.empty()&&q0.top()==q1.top()) q0.pop(),q1.pop();
return q0.top();
}
inline signed Pot(){
rr int x=Top(); Pop(x);
rr int ans=Top()+x;
Push(x);
return ans;
}
}A[N],B[N],Ans;
inline void Ans_Pop(int x){if (A[x].Size()>1) Ans.Pop(A[x].Pot());}
inline void Ans_Push(int x){if (A[x].Size()>1) Ans.Push(A[x].Pot());}
inline void switch_off(int x){
Ans_Pop(x),A[x].Push(0),Ans_Push(x);
for (rr int X=x;fat[X];X=fat[X]){
Ans_Pop(fat[X]);
int DIS=Dis(fat[X],x);
if (!B[X].Size())
B[X].Push(DIS),A[fat[X]].Push(DIS);
else{
int now=B[X].Top(); B[X].Push(DIS);
if (now<DIS)
A[fat[X]].Pop(now),A[fat[X]].Push(DIS);
}
Ans_Push(fat[X]);
}
}
inline void switch_on(int x){
Ans_Pop(x),A[x].Pop(0),Ans_Push(x);
for (rr int X=x;fat[X];X=fat[X]){
Ans_Pop(fat[X]);
int now=B[X].Top(),DIS=Dis(fat[X],x);
if (now>DIS) B[X].Pop(DIS);
else {
B[X].Pop(now);
if (!B[X].Size()) A[fat[X]].Pop(now);
else if (B[X].Top()<now)
A[fat[X]].Pop(now),A[fat[X]].Push(B[X].Top());
}
Ans_Push(fat[X]);
}
}
signed main(){
cnt=n=iut(),lg[0]=-1,two[0]=1,Ans.Push(0);
for (rr int i=1;i<18;++i) two[i]=two[i-1]<<1;
for (rr int i=1;i<n;++i){
rr int x=iut(),y=iut(),w=iut();
e[++et]=(node){y,w,as[x]},as[x]=et;
e[++et]=(node){x,w,as[y]},as[y]=et;
}
for (rr int i=1;i<=et;++i) lg[i]=lg[i>>1]+1;
big[0]=SIZ=n,Dfs(1,0);
for (rr int j=1;j<=lg[tot];++j)
for (rr int i=1;i+two[j]-1<=tot;++i)
f[i][j]=Get_Min(f[i][j-1],f[i+two[j-1]][j-1]);
dfs(1,root=0),dfs(root,0),dp(root);
for (rr int i=1;i<=n;++i) switch_off(i);
for (rr int Q=iut();Q;--Q){
rr char c=getchar();
while (!isalpha(c)) c=getchar();
if (c=='A'){
if (!cnt) for (rr int o=0;o<22;++o) Putchar(S[o]);
else if (cnt==1) Putchar(48);
else print(Ans.Top());
Putchar(10);
}else{
rr int x=iut(); v[x]^=1;
if (!v[x]) --cnt,switch_on(x);
else ++cnt,switch_off(x);
}
}
Flush();
return 0;
}

分析

但是在 QTREE4 - Query on a tree IV 就一直TLE。

考虑LCT,维护深度最浅/最深的白点的最大距离,由于虚子树的答案也要维护所以用两个可删堆记录链和答案,然后一样拼接一下

但是SPOJ上只能用multiset过,我也不知道为什么


代码

#include <cstdio>
#include <cctype>
#include <queue>
using namespace std;
const int N=100011,inf=1e9;
struct node{int y,w,next;}e[N<<1];
int W[N],a[N],as[N],n,et=1,ans;
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
struct Heap{
priority_queue<int>q0,q1;
int Size(){return q0.size()-q1.size();}
void Push(int x){q0.push(x);}
void Pop(int x){q1.push(x);}
int Top(){
while (!q1.empty()&&q0.top()==q1.top()) q0.pop(),q1.pop();
return q0.top();
}
int Pot(){
int x=Top(); Pop(x);
int ans=Top()+x;
Push(x);
return ans;
}
}A[N],B[N];
struct Splay{
int lmx[N],rmx[N],mx[N],son[N][2],fat[N],w[N],rev[N],stac[N],TOP;
bool unroot(int x){return son[fat[x]][0]==x||son[fat[x]][1]==x;}
bool Is_R(int x){return son[fat[x]][1]==x;}
void pup(int x){
w[x]=w[son[x][0]]+w[son[x][1]]+W[x];
int xu=a[x],now=0;//与左子树相连实际是其祖先需要加上到父节点的边
if (B[x].Size()) xu=max(xu,now=B[x].Top()),now=max(now,0);
int L=max(xu,W[x]+rmx[son[x][0]]),R=max(xu,lmx[son[x][1]]);
lmx[x]=max(lmx[son[x][0]],w[son[x][0]]+W[x]+R);
rmx[x]=max(rmx[son[x][1]],w[son[x][1]]+L);
mx[x]=max(L+lmx[son[x][1]],rmx[son[x][0]]+W[x]+R);
mx[x]=max(mx[x],max(mx[son[x][0]],mx[son[x][1]]));
if (A[x].Size()) mx[x]=max(mx[x],A[x].Top());
if (B[x].Size()>1) mx[x]=max(mx[x],B[x].Pot());
if (!a[x]) mx[x]=max(mx[x],now);
}
void Rev(int x){swap(son[x][0],son[x][1]),rev[x]^=1;}
void pdown(int x){
if (rev[x]){
if (son[x][0]) Rev(son[x][0]);
if (son[x][1]) Rev(son[x][1]);
rev[x]=0;
}
}
void rotate(int x){
int Fa=fat[x],FFa=fat[Fa],wh=Is_R(x),t=son[x][wh^1];
if (unroot(Fa)) son[FFa][Is_R(Fa)]=x;
son[x][wh^1]=Fa,son[Fa][wh]=t;
if (t) fat[t]=Fa; fat[Fa]=x,fat[x]=FFa;
pup(Fa);
}
void splay(int x){
int y=x; stac[TOP=1]=y;
while (unroot(y)) stac[++TOP]=y=fat[y];
for (;TOP;--TOP) pdown(stac[TOP]);
for (;unroot(x);rotate(x)){
int Fa=fat[x];
if (unroot(Fa)) rotate((Is_R(x)^Is_R(Fa))?x:Fa);
}
pup(x);
}
void Access(int x){
for (int y=0;x;x=fat[y=x]){
splay(x);
if (son[x][1]) A[x].Push(mx[son[x][1]]),B[x].Push(lmx[son[x][1]]);
if (y) A[x].Pop(mx[y]),B[x].Pop(lmx[y]);
son[x][1]=y,pup(x);
}
} }Tre;
void dfs(int x,int fa){
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fa){
Tre.fat[e[i].y]=x,W[e[i].y]=e[i].w,dfs(e[i].y,x);
A[x].Push(Tre.mx[e[i].y]),B[x].Push(Tre.lmx[e[i].y]);
}
Tre.pup(x);
}
int main(){
n=iut();
for (int i=1;i<n;++i){
int x=iut(),y=iut(),w=iut();
e[++et]=(node){y,w,as[x]},as[x]=et;
e[++et]=(node){x,w,as[y]},as[y]=et;
}
for (int i=0;i<=n;++i) Tre.lmx[i]=Tre.rmx[i]=Tre.mx[i]=-inf;
dfs(1,0),ans=Tre.mx[1];
for (int Q=iut();Q;--Q){
char ch=getchar();
while (!isalpha(ch)) ch=getchar();
if (ch=='A'){
if (ans<0) puts("They have disappeared.");
else print(ans),putchar(10);
}else{
int x=iut();
Tre.Access(x),Tre.splay(x),
a[x]=Tre.mx[0]-a[x],
Tre.pup(x),ans=Tre.mx[x];
}
}
return 0;
}

#点分树 or LCT#洛谷 4115 Qtree4的更多相关文章

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

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

  2. 洛谷 4115 Qtree4——链分治

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

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

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

  4. 树状数组 洛谷P3616 富金森林公园

    P3616 富金森林公园 题目描述 博艾的富金森林公园里有一个长长的富金山脉,山脉是由一块块巨石并列构成的,编号从1到N.每一个巨石有一个海拔高度.而这个山脉又在一个盆地中,盆地里可能会积水,积水也有 ...

  5. AC日记——【模板】树链剖分 洛谷 P3384

    题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...

  6. 【模板】树的重心 洛谷P1364 医院设置

    P1364 医院设置 题目描述 设有一棵二叉树,如图: 其中,圈中的数字表示结点中居民的人口.圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接 ...

  7. [洛谷P1198/BZOJ1012][JSOI2008] 最大数 - 树状数组/线段树?

    其实已经学了树状数组和线段树,然而懒得做题,所以至今没写多少博客 Description 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数 ...

  8. 洛谷P4344 脑洞治疗仪 [SHOI2015] 线段树+二分答案/分块

    !!!一道巨恶心的数据结构题,做完当场爆炸:) 首先,如果你用位运算的时候不小心<<打成>>了,你就可以像我一样陷入疯狂的死循环改半个小时 然后,如果你改出来之后忘记把陷入死循 ...

  9. 洛谷 P5706 【深基2.例8】再分肥宅水

    题目连接: P5706 [深基2.例8]再分肥宅水 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 我提交的: 1 #include<iostream> 2 #inclu ...

  10. 洛谷P1972 【[SDOI2009]HH的项链】

    这道题想了很久,发题解是为了理解的更深刻一点...(管理放我过好嘛qwq) 步入正题:这道题应该是很多做法,我选择的是离线+树状数组. 首先输入数组.用fisrt数组先记录元素最开始出现的位置,对应的 ...

随机推荐

  1. OpenCV开发笔记(六十三):红胖子8分钟带你深入了解SIFT特征点(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  2. 基于kubeadm部署k8s1.80.0

    k8s搭建 硬件要求 测试环境 # master 2核 4G 20G # node 4核 8G 40G 生产环境 # master 8核 16G 100G # node 16核 64G 500G 方式 ...

  3. AI 让观众成为 3D 版《老友记》的导演了?

    <老友记>上线 3D 版了? 允许用户旋转镜头,且从近景切换到全景观看故事? 今年出炉的 3D 方向 AI 项目 SitCom3D,能够自动补齐<老友记>原剧中的三维拍摄空间, ...

  4. 03、Etcd 客户端常用命令

    上一讲我们安装 etcd 服务端,这一讲我们来一起学学如何使用 etcd 客户端常见的命令.文章内容来源于参考资料,如若侵权,请联系删除,谢谢. etcd可通过客户端命令行工具 etcdctl 对et ...

  5. 【Azure Redis 缓存】Lettuce 连接到Azure Redis服务,出现15分钟Timeout问题

    问题描述 在Java应用中,使用 Lettuce 作为客户端SDK与Azure Redis 服务连接,当遇见连接断开后,长达15分钟才会重连.导致应用在长达15分的时间,持续报错Timeout 问题解 ...

  6. 【Azure 媒体服务】记录使用Java调用Media Service API时候遇见的一些问题

    问题一:java.lang.IllegalArgumentException: Parameter this.client.subscriptionId() is required and canno ...

  7. Codeforces Round 829 (Div. 1)A1. Make Nonzero Sum (easy version)(思维找规律)

    先考虑无解的情况:当n为奇数时无解 相邻的两个元素一定可以变成0 \[a[i] != a[i + 1]时, 分成[i, i], 和[i + 1, i + 1] \] \[a[i] = a[i + 1] ...

  8. vscode 切换主侧栏可见性 原Ctrl+B 我改为了 Alt+P

    vscode 切换主侧栏可见性 原Ctrl+B 我改为了 Alt+P ctrl+b 总是想不起来

  9. STM32 SPI接口 DMA normal 和circual区别

    DMA有normal和circular两种模式. circular模式: 就调用这个函数一次就可以了,DMA一直开启,一帧数据发送完毕之后里面发送下一帧,中间没有停顿.这样确实是快了,也释放了CPU, ...

  10. c语言中静态链接库的创建和使用

    静态链接库的创建 静态链接库其实就相当于压缩包,其内部可以包含多个源文件.但需要注意的是,并非任何一个源文件都可以被加工成静态链接库,其至少需要满足以下 2 个条件: 源文件中只提供可以重复使用的代码 ...