首页 > 其他分享 >P3224 [HNOI2012]永无乡 题解

P3224 [HNOI2012]永无乡 题解

时间:2023-02-24 13:35:43浏览次数:51  
标签:ch val HNOI2012 int 题解 Splay fa P3224 id

典型Splay练习题。

开始建 \(n\) 个Splay,每一次建边用并查集判断是否在一个子图,不在就合并,即把一个Splay的所有点全插入到另一个Splay中,需要合并的点可以用vector存储。

但这样复杂度极限为 \(O(n^2\times \log(n))\),会T,所以要借助启发式合并。

证明启发式合并复杂度:

对于每一次合并,当 \(len_i=len_j\) 时合并时间复杂度越大,所以易证,对于每一个从 \(len_i=1\) 开始的Splay树,只需进行 \(\log(n)\) 次即可将合并规模达到 \(n\)。

所以启发式合并后的复杂度为 \(O(n\times\log^2(n))\)

附代码:

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int N=1e5+5;
vector<int>a[N];
struct node
{
int fa,ch[2],val,siz,cnt;
}t[N];
int n,cnt,root[N],p[N],m,f[N];
void newnode(int &x,int val,int fa)
{
x=++cnt;
t[x].fa=fa;
t[x].val=val;
t[x].cnt=t[x].siz=1;
}
void connect(int x,int fa,int son)
{
t[x].fa=fa;
t[fa].ch[son]=x;
}
bool ident(int x,int fa)
{
return t[fa].ch[1]==x;
}
void pushup(int x)
{
t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+t[x].cnt;
}
void rotate(int x)
{
int fa=t[x].fa,ff=t[fa].fa,k=ident(x,fa);
connect(t[x].ch[k^1],fa,k);
connect(fa,x,k^1);
connect(x,ff,ident(fa,ff));
pushup(fa),pushup(x);
}
void Splay(int x,int p=0,int topp=0)
{
if(!topp)root[p]=x;
while(t[x].fa!=topp)
{
int fa=t[x].fa,ff=t[fa].fa;
if(ff!=topp)ident(x,fa)^ident(fa,ff)?rotate(x):rotate(fa);
rotate(x);
}
}
void insert(int val,int &x,int num,int id=0,int to=0,int fa=0)
{
if(!x&&!id)newnode(x,val,fa),Splay(x,num);
else if(!x&&id)x=id,t[x].ch[0]=t[x].ch[1]=0,connect(id,fa,to),Splay(id,num);
else if(t[x].val>val)insert(val,t[x].ch[0],num,id,0,x);
else if(t[x].val<val)insert(val,t[x].ch[1],num,id,1,x);
else t[x].cnt++,Splay(x,num);
}
int getval(int k,int x,int num)
{
if(!x)return -1;
if(k<=0)
{
Splay(x,num);
return x;
}
if(k<=t[t[x].ch[0]].siz)return getval(k,t[x].ch[0],num);
int tmp=k-t[t[x].ch[0]].siz-t[x].cnt;
if(tmp<=0)
{
Splay(x,num);
return x;
}
else return getval(tmp,t[x].ch[1],num);
}
int afind(int x)
{
if(f[x]==x)return x;
return f[x]=afind(f[x]);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&p[i]);
f[i]=i;
a[i].push_back(i);
insert(p[i],root[i],i);
}
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
if(afind(u)!=afind(v))
{
int k=afind(v),kt=afind(u);
if(a[k].size()>a[kt].size())swap(k,kt);
int len=a[k].size();
for(int j=0;j<len;j++)
{
a[kt].push_back(a[k][j]);
insert(p[a[k][j]],root[kt],kt,a[k][j]);
}
f[k]=kt;
}
}
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
char opt;
scanf("%c",&opt);
while(opt!='B'&&opt!='Q')scanf("%c",&opt);
int x,y;
scanf("%d%d",&x,&y);
if(opt=='B')
{
if(afind(x)!=afind(y))
{
int k=afind(y),kt=afind(x);
if(a[k].size()>a[kt].size())swap(k,kt);
int len=a[k].size();
for(int j=0;j<len;j++)
{
a[kt].push_back(a[k][j]);
insert(p[a[k][j]],root[kt],kt,a[k][j]);
}
f[k]=kt;
}
}
if(opt=='Q')
{
int k=afind(x);
int ans=getval(y,root[k],k);
printf("%d\n",ans);
}
}
return 0;
}

标签:ch,val,HNOI2012,int,题解,Splay,fa,P3224,id
From: https://www.cnblogs.com/gmtfff/p/p3244.html

相关文章

  • P1763 埃及分数 题解
    做完后发现很多题解都是有些细节问题的,对于向上与向下取整非常混乱。第一次做迭代加深搜索的题,记录一下。所谓迭代加深搜索,就是在求搜索树的深度的问题中,枚举层数,取最优......
  • P4048 [JSOI2010]冷冻波 题解
    首先很好想到我们应该预处理出来每一个巫妖王能攻击到的精灵。那么这就是一个几何题。对于每一组精灵与巫妖王,设巫妖王坐标为\((x_1,y_1)\),精灵坐标为\((x_2,y_2)\)。......
  • P7221 [JSOI2010] 蔬菜庆典 题解
    本题解在求无解的情况下优化了下。通过分析样例,我们可以发现如果一个节点有多个Dlihc,那么这些Dlihc对应的权值必须一样,否则可以无限延伸下去。因为一号节点没有Tnera......
  • P3195 [HNOI2008]玩具装箱 题解
    首先先写dp方程非常简单\(\mathit{f}_{i}=\min(\mathit{f}_{j}+(\mathit{c}_{i}+i-j-1-L-\mathit{c}_{j})^2)\)(其中\(\mathit{c}_{i}\)表示长度前缀和)然后发现括号......
  • U259394 Gmt丶FFF 的基环树 题解
    题目链接:传送门之所以评黑,是因为实在是太难调了。(又回调了)。对于有$40%$的数据,$n\le3000$,这部分我们可以暴力删边,然后暴力求直径即可。那么对于$100%$的数据:首先......
  • P3977 [TJOI2015]棋盘 题解
    前制知识引导状态压缩动态规划:[P1896[SCOI2005]互不侵犯](https://www.luogu.com.cn/problem/P1896)矩阵加速优化:[P1962斐波那契数列](https://www.luogu.com.cn/prob......
  • vscode格式化和保存代码与eslint有冲突问题解决(亲测有效)
    1.问题描述vscode安装了eslint插件,在使用Vue的时候格式化和保存代码都会爆红2.原因因为在使用Vue进行开发我们一般都安装了Vetur插件来对.vue文件进行处理,Vetur自带了......
  • 云原生|kubernetes|CKA真题解析-------(6-10题)
    第六题:service配置 解析:考察两个知识点:deployment控制器内的port命名暴露一个pod内的端口到新建的服务内的这里有一个需要注意的地方,没有告诉你deployment控制器在哪个name......
  • Windows 技术篇 - 远程桌面连接不保存密码、每次都要输入密码问题解决
    https://blog.csdn.net/qq_38161040/article/details/120013883通过 gpedit.msc 打开本次组策略编辑器。选择 模板管理-系统-凭据分配-允许分配保存的凭据用......
  • 【题解】ARC156 A-C
    神仙的ARC。A.Non-AdjacentFlip题目分析:就是一个分类讨论,主要就是讨论一下只有\(2\)个\(1\)的情况。自己手模一下应该很好理解。代码:点击查看代码#include<b......