Loj#2474-「2018 集训队互测 Day 3」北校门外的未来【LCT】

正题

题目链接:https://loj.ac/p/2474


题目大意

开始有一个只有点111的图,一个点xxx能走到点yyy当且仅当路径(x,y)(x,y)(x,y)之间(不包括x,yx,yx,y)不存在编号比xxxyyy要大的节点。有mmm次操作:

  1. 新建一个编号为yyy的节点和xxx连接,保证编号不重复。
  2. 询问xxx走到yyy最少需要走多少次。

节点编号在1∼n1\sim n1n之间

1≤n≤105,1≤m≤5×1051\leq n\leq 10^5,1\leq m\leq 5\times 10^51n105,1m5×105


解题思路

神仙题。

考虑构造一个类似笛卡尔树的东西,我们每次找到编号最大的点作为中心然后连接向它分割出来的连通块的中心。(相当于找编号最大的点的点分树)

我们记原树为TTT,这棵树为T′T'T,那么在T′T'T上一个点能跳到的点肯定都是它的祖先。考虑怎么样的祖先能够被他跳到,若xxx能跳到它的祖先yyy,有两种情况

  1. yyyxxxT′T'T上的父节点
  2. TTT的路径(x,y)(x,y)(x,y)上距离yyy最近的点为zzz,如果T′T'Tzzzxxx的子树内,那么xxx能跳到yyy。(这个不难证明,因为这样x∼yx\sim yxy的路径上没有它的其他祖先)

并且还有一个性质,若xxx能跳到zzzyyy为他的父节点,那么yyy也能跳到zzz,因为显然yyy绕去xxx一圈回来都行。

那么根据这个性质从贪心的角度思考,若我们的询问为x,yx,yx,y距离较远,视为x,yx,yx,y同时跳到它的LCALCALCA,那在大部分时候我们x,yx,yx,y都往能到达的深度最浅的节点跳是优的。

事实上也是这样,我们考虑x,yx,yx,y跳到x′,y′x',y'x,y满足它们再往上跳深度就小于或等于LCALCALCA了,记此时的跳跃次数为ccc,那么答案肯定是c+2c+2c+2或者c+3c+3c+3
因为若x′x'xy′y'y都能跳到LCALCALCA,次数就是c+2c+2c+2,否则就都往上跳一步,这样x′x'xy′y'y一点是祖孙关系(记x′x'x深度小),又因为原来的x′x'x能跳上来,那么这个新的y′y'y也肯定能跳到那个位置,此时答案为c+3c+3c+3

好那么现在我们就只需要处理祖孙的问题了,我们要支持对于x,yx,yx,yxxx跳到不超过yyy的最少步数和位置。这样询问时我们跳到x′,y′x',y'x,y然后再查询x′x'xy′y'y能否到达LCALCALCA就好了。

GGG表示一棵树,对于点xxx它的父节点就是它在T′T'T上能过跳到的深度最小的节点。

那么先考虑一次加点对T′T'T的影响,如果x>yx>yx>y,那么yyy直接接在xxx的后面就好了,GGG上也是同理。如果x<yx<yx<y,那么则需要向上找到一个xxx的深度最浅的祖先zzz满足z<yz<yz<y然后将yyy插在它的上面。
先考虑此时yyy能够到达的点和原来zzz能够到达的点是一样的,直接在GGG上接替zzz的位置,zzz则先暂时接在yyy的后面。
然后需要注意的是此时xxx节点就是路径(z,y)(z,y)(z,y)上距离yyy最近的点,可以考虑利用这个性质来维护GGG。那此时能到达yyy节点的除了zzz以外,还有在T′T'T上路径(x,y)(x,y)(x,y)的节点能直接到达yyy
并且这些节点在GGG上会接在yyy的后面的当且仅当他们原来接的点比yyy要大。

这样说下来GGG似乎很难维护,因为既和T′T'T的位置有关有和GGG的位置有关。考虑维护另一张图G′G'G,在这张图上我们将边分为虚边实边,实边是在GGG上实际存在的边,虚边则是代表这条边连接的两个节点在GGG上拥有同一个父亲。

开始时我们尽量让它保持T′T'T的模样,对于一个(x,y,z)(x,y,z)(x,y,z)(与上文的意思相同),那么我们提出路径(z,x)(z,x)(z,x)将其接到yyy的后面,然后整条路径都变成虚边,xxxyyy的连接则变成实边。
会发现再到后面我们提路径(z,x)(z,x)(z,x)时会发现它在G′G'G被分割成若干段,我们将这些段拼接起来。我们再把连上的边在T′T'T上标记起来,会发现这个过程是一个类似于LCTLCTLCT的Access的过程,均摊下来是O(n)O(n)O(n)次操作。

因为有断边连接操作,所以上述的G′G'G我们需要用一个LCTLCTLCT来维护,同时还需要维护一个T′T'T以方便我们找到每一段的位置。
然后我们需要精准的找到每一个实边修改,我们可以维护一个实边的和,然后在SplaySplaySplay上二分位置暴力修改。

时间复杂度:O(nlog⁡2n)O(n\log^2 n)O(nlog2n)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=1e5+10;
struct node{int to,next;
}a[N<<1];
int n,m,tot,op[N*5],rx[N*5],ry[N*5];
int cnt,pos[N],ls[N],fa[N],down[N],low[N];
int siz[N],dep[N],son[N],top[N],rfn[N],ed[N];
stack<int> stk;vector<int> G[N];
void addl(int x,int y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return;
}
void dfs1(int x){while(!stk.empty()&&pos[stk.top()]>pos[x])down[stk.top()]=x,stk.pop();//考虑若y>x那么只有往y那部分跑的pos会小于pos[y] stk.push(x);siz[x]=1;for(int i=0;i<G[x].size();i++){int y=G[x][i];fa[y]=x;dep[y]=dep[x]+1;dfs1(y);siz[x]+=siz[y];if(siz[y]>siz[son[x]])son[x]=y;}return;
}
void dfs2(int x){rfn[x]=++cnt;if(son[x]){top[son[x]]=top[x];dfs2(son[x]);}for(int i=0;i<G[x].size();i++){int y=G[x][i];if(y==son[x])continue;top[y]=y;dfs2(y);}ed[x]=cnt;return;
}
int LCA(int x,int y){while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);x=fa[top[x]];}return (dep[x]<dep[y])?x:y;
}
int gtop(int x,int y){while(top[x]!=top[y]){if(fa[top[x]]==y)return top[x];x=fa[top[x]];}return son[y];
}
bool gfir(int x,int y){int z=gtop(x,y);return (rfn[x]<=rfn[low[z]]&&rfn[low[z]]<=ed[x]);
}
struct LCT{int t[N][2],fa[N],cfa[N],w[N],c[N],son[N];bool Nroot(int x){return fa[x]&&(t[fa[x]][0]==x||t[fa[x]][1]==x);}bool Direct(int x){return t[fa[x]][1]==x;}void PushUp(int x){w[x]=w[t[x][0]]+w[t[x][1]]+c[x];return;}void Rotate(int x){int y=fa[x],z=fa[y];int xs=Direct(x),ys=Direct(y);int w=t[x][xs^1];if(Nroot(y))t[z][ys]=x;t[y][xs]=w;t[x][xs^1]=y;if(w)fa[w]=y;fa[y]=x;fa[x]=z;PushUp(y);PushUp(x);return;}void Splay(int x){while(Nroot(x)){int y=fa[x];if(!Nroot(y))Rotate(x);else if(Direct(x)==Direct(y))Rotate(y),Rotate(x);else Rotate(x),Rotate(x);}return;}void Access(int x){for(int y=0;x;y=x,x=fa[x])Splay(x),t[x][1]=y,PushUp(x);return;}int MakeTop(int x){Splay(x);if(!t[x][0])return fa[x];x=t[x][0];while(t[x][1])x=t[x][1];Splay(x);t[x][1]=0;PushUp(x);return x;}void Mdf(int x,int w){Splay(x);c[x]=w;PushUp(x);return;}int GetTop(int x){Splay(x);while(t[x][0])x=t[x][0];return x;}int GetBot(int x){Splay(x);while(t[x][1])x=t[x][1];return x;}void Ins(int x,int y){if(x>y){fa[y]=cfa[y]=x;c[y]=w[y]=1;return;}int u,v;u=MakeTop(v=down[y]);Mdf(y,c[v]);Mdf(v,!u);fa[y]=u;fa[v]=y;if(son[u]==v)son[u]=y;if(u)son[y]=v;int z=0,now=0,low=x;while(x){Splay(x);t[x][1]=z;PushUp(x);if(w[x]){while(x){if(w[t[x][1]])x=t[x][1];else if(c[x])break;else x=t[x][0];}if(x>y)break;u=MakeTop(x);if(u>y)break;Splay(low);t[low][1]=0;if(son[low]){Splay(son[low]);fa[son[low]]=u;Mdf(son[low],1);son[low]=0;}int pre=cfa[x];Mdf(x,0);x=GetBot(x);Splay(x);if(now)fa[now]=x,son[x]=t[x][1]=GetTop(now);now=x;z=0;low=x=pre;}else z=x,x=fa[x];}cfa[y]=cfa[down[y]];cfa[down[y]]=y;if(now)now=GetTop(now),Mdf(now,1),fa[now]=y;return;}pair<int,int> Ask(int x,int y){if(x==y)return mp(0,0);Access(x);Splay(x);int dis=0,top=0,pre=x;while(x)if(x<y)top=x,x=t[x][0];else x=t[x][1];Splay(top);x=t[top][1];if(!w[x])return mp(0,pre);dis=w[x];while(x){if(w[t[x][0]])x=t[x][0];else if(c[x]){if(t[x][0]){x=t[x][0];while(t[x][1])x=t[x][1];return mp(dis,x);}return mp(dis,top);}else top=x,x=t[x][1];}return mp(dis,top);}int ct=0;int Query(int x,int y){ct++;if(ct==10)ct++,ct--;if(x==y)return 0;if(x>y)swap(x,y);int lca=LCA(x,y);if(lca==y){pair<int,int> A=Ask(x,y);int ans=A.first+2;if(gfir(A.second,y))ans--;return ans;}pair<int,int> A=Ask(x,lca);pair<int,int> B=Ask(y,lca);int ans=A.first+B.first+3;if(gfir(A.second,lca)&&gfir(B.second,lca))ans--;return ans;}
}T;
int find(int x)
{return (fa[x]==x)?(x):(fa[x]=find(fa[x]));}
int main()
{scanf("%d%d",&n,&m);n=1;for(int i=1;i<=m;i++){scanf("%d%d%d",&op[i],&rx[i],&ry[i]);n=max(n,ry[i]);if(op[i]==1)addl(rx[i],ry[i]),addl(ry[i],rx[i]),pos[ry[i]]=i;}for(int i=1;i<=n;i++)fa[i]=i;for(int x=1;x<=n;x++)for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(find(y)<x)G[x].push_back(find(y)),fa[find(y)]=x;}fa[n]=0;dep[n]=1;dfs1(n);top[n]=n;dfs2(n);for(int x=1;x<=n;x++)for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(x>y)low[gtop(y,x)]=y;}//low[x]表示点x子树内离它父节点最近的点for(int i=1;i<=m;i++){if(op[i]==1)T.Ins(rx[i],ry[i]);else printf("%d\n",T.Query(rx[i],ry[i]));}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317421.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CF407 E. k-d-sequence(线段树+单调栈)

文章目录CF407 E. k-d-sequenceproblemsolutioncodeCF407 E. k-d-sequence problem solution special case&#xff0c;d0d0d0&#xff0c;相当于寻找最长的一段数字相同的区间 other case&#xff0c;如果要满足公差为ddd等差序列 区间内每个数在模ddd意义下同余每个数互不…

D. Binary Literature

D. Binary Literature 题意&#xff1a; 给三个长度为2 * n的01串&#xff0c;让你构造一个长度小于3 * n的字符串&#xff0c;使得这个串至少包含两个01串 题解&#xff1a; 很巧妙的构造题 三个指针分别指向三个串&#xff0c;因为是01串&#xff0c;所以一定存在两个字符…

安逸:鼠绘《诗与远方》

【作品名称】《诗与远方》【作者介绍】徐安&#xff08;笔名安逸&#xff0c;常州&#xff09;&#xff0c;PPT专家&#xff0c;鼠绘专家。平面设计专业&#xff0c;6年PPT设计经验&#xff1b;历届江苏省PPT制作大赛一等奖获得者&#xff0c;PA口袋动画重要合作人。PPT动画制作…

洛谷P4292:重建计划(点分治、单调队列)

解析 第一眼&#xff1a;Wow这么水的黑&#xff1f;&#xff1f; 然后写了一发二分套线段树的3log代码上去 T到飞起&#xff0c;只有40… 无奈瞅了一眼标签&#xff1a;单调队列 对啊 于是又写了一个上去 20 … 好啊 然后就摆烂了 qwq 果然黑题没有一个好东西 一个关键的思…

E. Colorings and Dominoes(未解决)

E. Colorings and Dominoes 题意&#xff1a; n * m的格子&#xff0c;分为黑白格子&#xff0c;白格子可以染成蓝色或者红色&#xff0c;一个1 * 2的多米诺骨牌&#xff0c;可以覆盖两个连续的水平的红色格子或者两个连续的竖着的蓝色格子&#xff0c;对于一个染色方案&…

[HNOI2016]网络(树链剖分+线段树+大根堆)

[HNOI2016]网络 problem solution 另辟蹊径&#xff0c;不把交互请求赋在新增路径上&#xff0c;反而把交互请求赋在树上除去该请求路径覆盖点的其它点上 显然&#xff0c;路径问题树剖是非常可以的、 那么一个点上的信息就表示所有不经过该点的交互请求&#xff0c;用堆…

P4557-[JSOI2018]战争【凸包,闵可夫斯基和】

正题 题目连接:https://www.luogu.com.cn/problem/P4557 题目大意 给出两个点集A,BA,BA,B&#xff0c;qqq次询问给出一个向量vvv&#xff0c;询问将BBB中所有点加上向量vvv后两个集合的凸包是否有交。 1≤n,m,q≤1051\leq n,m,q\leq 10^51≤n,m,q≤105 解题思路 闵可夫斯基和…

IdentityServer4实战 - JWT Token Issuer 详解

一.前言本文为系列补坑之作&#xff0c;拖了许久决定先把坑填完。下文演示所用代码采用的 IdentityServer4 版本为 2.3.0&#xff0c;由于时间推移可能以后的版本会有一些改动&#xff0c;请参考查看&#xff0c;文末附上Demo代码。本文所诉Token如无特殊说明皆为 JWT Token。众…

P3834 【模板】可持久化线段树 2(整体二分做法)

P3834 【模板】可持久化线段树 2&#xff08;主席树&#xff09; 我们详细讲讲这个整体二分如何求区间第k小 我们都知道二分可以求出区间里某个想要的值&#xff0c;如果有很多询问&#xff0c;我们对每个询问都进行二分&#xff0c;复杂度就是O(QNlog(1e9))铁超&#xff0c;那…

YBTOJ洛谷P3292:幸运数字(线性基、点分治/倍增)

解析 虽然使用三个log的倍增算法艹过去了 但是我们还是来聊聊正解吧 考虑点分治 对于当前的根&#xff0c;dfs求出联通块内每个点到当前根的线性基 一条路径的答案应该在路径出现上第一个成为根的点时统计到 具体来说&#xff0c;就是路径的两端点在同一个solve函数的不同子树…

AGC053E-More Peaks More Fun【计数】

正题 题目链接:https://atcoder.jp/contests/agc053/tasks/agc053_e 题目大意 给出nnn个二元组(ai,bi)(a_i,b_i)(ai​,bi​)&#xff0c;求有多少个1∼n1\sim n1∼n的排列ppp满足&#xff1a; 你可以将一些(ai,bi)(a_i,b_i)(ai​,bi​)变为(bi,ai)(b_i,a_i)(bi​,ai​)定义序…

「JOISC 2020 Day4」治疗计划(线段树+dijkstra最短路)

「JOISC 2020 Day4」治疗计划 description solution 设dpi:1−Ridp_i:1-R_idpi​:1−Ri​ 都能被救治成功的最小花费 两个治疗方案[Li,Ri],[Lj,Rj][L_i,R_i],[L_j,R_j][Li​,Ri​],[Lj​,Rj​]能够合并成完整的健康区间的条件为Ri−Lj1≥∣Ti−Tj∣R_i-Lj1\ge |T_i-T_j|Ri​…

胡浩:人人能学的AI《从零开始机器学习》苏州.NET俱乐部课程分享

【课程名称】《从零开始机器学XI》【老师介绍】胡浩&#xff0c;微软最有价值专家&#xff08;MVP&#xff0c;十余届多方向&#xff09;&#xff0c;微软技术大会讲师。云、数据中心基础架构、全栈虚拟化、企业移动管理等领域的架构师及顾问。AI/ML等新技术的爱好者&#xff0…

整体二分例题

参考oi wiki 引入&#xff1a; 有一部分题可以使用二分的办法来解决。但是当这种题目有多次询问且每次询问我们对每个查询都直接二分&#xff0c;可能会收获一个 TLE。这时候我们就会用到整体二分。整体二分的主体思路就是把多个查询一起解决。&#xff08;所以这是一个离线算…

P8338-[AHOI2022]排列【质因数分解】

正题 题目链接:https://www.luogu.com.cn/problem/P8338 题目大意 给出一个排列pip_ipi​&#xff0c;定义ai0i,aikapik−1a_i^0i,a_i^ka_{p_i}^{k-1}ai0​i,aik​api​k−1​。 对于排列PPP&#xff0c;定义F(P)F(P)F(P)表示最小的一个正整数kkk满足Pk1PP^{k1}PPk1P。 定义…

CF1100F Ivan and Burgers(线性基)

解析 做幸运数字的时候逛题解区爬过来的 挺妙的 把所有询问离线下来&#xff0c;按右端点排序 贪心的让最高位更高的向量出现的尽可能向右 实现上可以把线性基里的向量和当前的数swap来实现 代码就非常好写了 代码 #include<bits/stdc.h> using namespace std; #defi…

[APIO2013]机器人(DP+SPFA最短路)

[APIO2013]机器人 description solution dpl,r,i,j:dp_{l,r,i,j}:dpl,r,i,j​: 在(i,j)(i,j)(i,j)位置合并编号为[l,r][l,r][l,r]区间内的所有机器人的最小花费 toi,j,k:to_{i,j,k}:toi,j,k​: 从(i,j)(i,j)(i,j)以kkk方向推机器人最终停止的位置&#xff0c;用dfs记忆化搜索…

IdentityServer4实战 - 与API单项目整合

一.前言我们在实际使用 IdentityServer4 的时候&#xff0c;可能会在使用 IdentityServer4 项目添加一些API&#xff0c;比如 找回密码、用户注册、修改用户资料等&#xff0c;这些API与IdentityServer4怎么共存在一个项目呢&#xff1f;二.整合1.首先在 Startup.cs 中添加 Ide…

P2305 [NOI2014] 购票(点分治、斜率优化)

解析 第一道完全自己做出来的黑题awa &#xff08;如果不算那道感觉完全是恶评的石油的话&#xff09; 然而连写带调整了3.5h… 容易想到链的做法 设ancxanc_xancx​表示x的祖先,disxdis_xdisx​表示x到1的距离 则有&#xff1a; dpvmin⁡disv−lv<disu,u∈ancv(dpupv(dis…

HDU1394(权值线段树)

HDU1394(权值线段树) 题意&#xff1a; 给定一个0到n-1的数字组成的序列&#xff0c;可以将序列进行左移任意次&#xff0c;求所能组成序列的逆序对的最小值 题解&#xff1a; 利用权值线段树&#xff0c;我们先求出当前序列所能组成的逆序对&#xff0c; 然后依次左移动 当…