码迷,mamicode.com
首页 > 其他好文 > 详细

LCT来惹( ? ?ω?? )?

时间:2020-09-24 21:58:31      阅读:37      评论:0      收藏:0      [点我收藏+]

标签:hide   algorithm   ++   ring   etc   std   传递   观点   har   

  • 让我们先把没学完的IDFT放在这里
  • 技术图片
    #include <stdio.h>
    #include <algorithm>
    #include <cstring>
    
    const int maxn=200000;
    typedef std:complex<double> com;//typedef 真实放前 define 真实放后
    com eps[maxn],ieps[maxn];//单位根以及其共轭
    //再次注意,我们用IDFT求的都是2^m的次数的多项式,并且假定n=2m
    
    inline void trans(int n,int x[],int w[])//使用复数还是共轭 
    {
        for(int i=0,j=0;i!=n;i++)//i是正常加法,如果说两个没有换过,我们换一下 
        {
            if(i<j) swap(x[i],x[j]);
            for(int l=n>>1;(j^=l)<l;l>>=1);//每次都是算0-》1是大于l而1->0小于l 
        }
    } 
    View Code

     

然后,就让我们进入LCT的世界

首先 show the code

技术图片
#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <cctype>

using namespace std;
const int maxn=100200;
struct Node
{
    int lx,rx,fa,rev;
    #define l(x) t[x].lx
    #define r(x) t[x].rx
    #define rev(x) t[x].rev
    #define fa(x) t[x].fa 
}t[maxn];
int n,m;
int que[maxn],top;

inline int read()
{
    int x=0,b=1;char c=getchar();
    while(!isdigit(c)) b=c==-?-1:1,c=getchar();
    while(isdigit(c)) x=x*10+c-0,c=getchar();
    return x*b;
}

inline void down(int x)
{
    if(rev(x))
    {
        swap(l(x),r(x));
        if(l(x)) rev(l(x))^=1;
        if(r(x)) rev(r(x))^=1;
        rev(x)=0;
    }
}
inline int isroot(int x)
{
    if(!fa(x)) return true;
    return x!=l(fa(x))&&x!=r(fa(x));
}
inline void rot(int x)//因为我们只在splay当中rot,并且已经把涉及的节点全部都down了一遍了,就不用再在里面进行判断了 
{
    int y=fa(x),z=fa(y),b=x==l(y)?r(x):l(x);
    
    if(z&&!isroot(y)) (y==l(z)?l(z):r(z))=x;//这里要设置z的左右儿子,根据lct的性质,我们设置左右儿子时,可能父亲左右儿子都是自己,所以更要小心
    fa(x)=z,fa(y)=x;if(b) b?fa(b)=y:0;//不知道这一步有没有影响 
    
    
    //
    //这一步果然有影响,因为我们判断isroot的条件就是他的fa(X)或者他的fa左右儿子都不是他,但是先提前设置fa(y)=x就会导致爆炸
    //所以,以后再次编写代码的时候一定要考虑好顺序性问题
    //好习惯,我们可以将有逻辑顺序性的代码存放在一起便于查看
    //总结over 
    if(x==l(y)) r(x)=y,l(y)=b;
    else l(x)=y,r(y)=b;
    return;
}
inline int war(int x)
{
    return r(fa(x))==x;
}
inline void splay(int x)
{
    que[top=0]=x;
    for(int y=x;!isroot(y);y=fa(y)) que[++top]=fa(y);//从x直到根节点上面的路径都要被保存//在注意,我们这里存入que的是fa(y)而不是y为什么呢 
    for(int i=top;i>=0;i--) down(que[i]);//懒标记的性质,从上往下传递标记 
    while(!isroot(x))
    {
        if(!isroot(fa(x)))//为什么是判断isrootfa(x)而不是我们之前的fa[fa[x]]!=tar 
        rot(war(fa(x))==war(x)?fa(x):x);
        rot(x);
    } 
    return ;
}
inline void access(int x)
{
    for(int y=0;x;y=x,x=fa(x))
    {
        splay(x);r(x)=y;//右边连接到上一个x,相当于将x的整棵树和y右子树做了个替换 
        if(y) fa(y)=x;
    }
}

inline int getroot(int x)
{
    access(x);splay(x);
    while(down(x),l(x)){//先down后找 
        x=l(x);
    }
    splay(x);return x;
}
inline void makeroot(int x)
{
    access(x);splay(x);
    rev(x)^=1;
}
inline void bulid(int x,int y)
{
    makeroot(x);fa(x)=y;
    return;
}
inline void Delete(int x,int y)
{
    makeroot(x);access(y);splay(y);
    l(y)=0;fa(x)=0;return;//在平衡树当中直接操作 
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        char s[200];
        scanf("%s",s);
        if(s[0]==Q)
        {
            //printf("1\n");
            if(getroot(read())==getroot(read())) printf("Yes\n");
            else printf("No\n");
        }
        else if(s[0]==C) bulid(read(),read());//printf("2\n");
        else Delete(read(),read());
    }
    return 0;
}
View Code

 

动态树(准确说是维护森林)之一,支持连边,断边,求链上权值和等操作。

  • 动态树运用的是拆分和抽象典型表达的思想
  • 利用树链剖分的性质,我们通过维护每一条链来维护整个森林
  • 链的维护通过一颗平衡树的实现
  1. 因为实链节点深度一定不同,则维护左节点深度一定小于实链,右节点一定大于实链
  2. 这样做,最左节点为实链顶,最右为实链底
  • 这样,根据抽象表达和自相似的观点,所有的实链,我们只需要维护他们所对应的实树(可能)的根节点,就可以把它们统一在一起
  1. 每一颗树可以由若干个实链拼接而成
  2. 实链间的转移通过左顶节点的pathparent来实现
  3. 整体树的表达通过维护统一的对应实树的根节点来实现
  4. 这样就够了
  • 具体实现使用splay就可以

LCT来惹( ? ?ω?? )?

标签:hide   algorithm   ++   ring   etc   std   传递   观点   har   

原文地址:https://www.cnblogs.com/ILHYJ/p/13723673.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!