LCT(GCD Tree,HDU 5398)

来源:互联网 发布:windows svn 钩子 编辑:程序博客网 时间:2024/04/25 20:38

值得注意的是,千万别把LCT的结构当成真实的树的结构。


题目链接:https://vjudge.net/problem/HDU-5398


就是要快速求两点间路径上距离最短的边。

比如求u和v。

那就先mroot(u),使u成为根。

然后再access(v),打通u,v之间的路径,使得u和v在同一棵Auxiliary Tree中。此时u是第一个值,v是最后一个值。这棵Auxiliary Tree包含且仅包含u到v路径上的所有节点。

然后Splay(v),使得v伸展到这棵Auxiliary Tree的根。因为v是最后一个节点,所以此时v没有右儿子。

如果我们知道一个节点所在子树(对于其所在的Auxiliary Tree而言)所代表的路径上的最短边以及对应的节点编号,

那么上述问题就可以直接解决了。


所以我们要维护一个节点所在子树所代表的路径上的最短边以及对应的节点编号。


具体而言就是要维护以下值

1、节点所在子树所代表的路径上的最短边长。

2、最短变长所对应的两个端点。

3、节点所在子树所代表的路径的头和尾。(具体就是中序遍历第一个访问和最后一个访问的节点)


1和2是我们需要的值。

3可以帮助我们从儿子转移到父亲。


关于数论方面的优化

对于一个数x,我们只需要枚举它的质因数y,然后考虑z=x/y。尝试将x与z连边。一定最优。

因为如果y不是质因数,比如y=a*b,那么z=x/y=x/(a*b)=(x/a)/b。

由于我们是从小到大加点,所以之前已经考虑过(x/a)这个数了,对于(x/a)这个数当然也已经考虑过和z=(x/a)/b连边了,因此不用再重复考虑。

1<=n<=1e5,质因数的个数不超过10个。所以总的时间复杂度为O(10nlogn)。

Eratosthenes筛法用于筛出质数。稍加改造就可以筛出质因数或因数。时间复杂度都为O(nlogn)。


代码

#include<stdio.h>#include<algorithm>#include<vector>#include<math.h>//#include<windows.h>using namespace std;typedef long long ll;const int maxn = 100010;const int inf = 0x3f3f3f3f;struct node{    int val;    int fa,ch[2];    bool reverse,is_root;    int MIN;    int u,v;    int pp[2];    void init(int x)    {        val=x;        fa=ch[0]=ch[1]=0;        reverse=0;        is_root=1;        MIN=inf;        u=v=-1;        pp[0]=pp[1]=x;    }}T[maxn];int gcd(int a,int b){    return !b?a:gcd(b,a%b);}void pushreverse(int x){    if(!x) return;    swap(T[x].ch[0],T[x].ch[1]);    swap(T[x].pp[0],T[x].pp[1]);    T[x].reverse^=1;}void pushdown(int x){    if(T[x].reverse)    {        pushreverse(T[x].ch[0]);        pushreverse(T[x].ch[1]);        T[x].reverse=false;    }}void pushup(int x){    T[x].MIN=inf;    T[x].u=T[x].v=-1;    T[x].pp[0]=T[x].pp[1]=x;    pushdown(x);    for(int i=0;i<2;i++)    {        if(T[x].ch[i])        {            T[x].pp[i]=T[T[x].ch[i]].pp[i];            if(T[x].MIN>T[T[x].ch[i]].MIN)            {                T[x].MIN=T[T[x].ch[i]].MIN;                T[x].u=T[T[x].ch[i]].u;                T[x].v=T[T[x].ch[i]].v;            }            int GCD=gcd(T[x].val,T[T[x].ch[i]].pp[i^1]);            if(T[x].MIN>GCD)            {                T[x].MIN=GCD;                T[x].u=x;                T[x].v=T[T[x].ch[i]].pp[i^1];            }        }    }}int getson(int x){    return x==T[T[x].fa].ch[1];}void rotate(int x){    if(T[x].is_root) return;    int k=getson(x);    int fa=T[x].fa;    int fafa=T[fa].fa;    pushdown(fa);    pushdown(x);    T[fa].ch[k]=T[x].ch[k^1];    if(T[x].ch[k^1]) T[T[x].ch[k^1]].fa=fa;    T[x].ch[k^1]=fa;    T[fa].fa=x;    T[x].fa=fafa;    if(T[fa].is_root)    {        T[fa].is_root=false;        T[x].is_root=true;    }    else    {        T[fafa].ch[fa==T[fafa].ch[1]]=x;    }    pushup(fa);    pushup(x);}void push(int x){    if(!T[x].is_root) push(T[x].fa);    pushdown(x);}void Splay(int x){    push(x);    for(int fa;!T[x].is_root;rotate(x))    {        if(!T[fa=T[x].fa].is_root)        {            rotate((getson(x)==getson(fa))?fa:x);        }    }}void access(int x){    int y=0;    do    {        Splay(x);        T[T[x].ch[1]].is_root=true;        T[T[x].ch[1]=y].is_root=false;        pushup(x);        x=T[y=x].fa;    }while(x);}void mroot(int x){    access(x);    Splay(x);    pushreverse(x);}void link(int u,int v){    mroot(u);    T[u].fa=v;}void cut(int u,int v){    mroot(u);    access(v);    Splay(v);    pushdown(v);    T[T[v].ch[0]].fa=T[v].fa;    T[T[v].ch[0]].is_root=true;    T[v].fa=0;T[v].ch[0]=0;    pushup(v);}vector<int>vec[maxn];int vis[maxn];ll a[maxn];ll ans;void getpri(){    for(int i=2;i<maxn;i++) if(!vis[i])        for(int j=i;j<maxn;j+=i)        {            vis[j]=1;            vec[j].push_back(i);        }}void debug(){    puts("----------");    for(int i=1;i<=21;i++)    {        printf("i:%d fa:%d le:%d ri:%d rt:%d rev:%d lll:%d rrr:%d\n",i,T[i].fa,T[i].ch[0],T[i].ch[1],T[i].is_root,T[i].reverse,T[i].pp[0],T[i].pp[1]);    }    puts("----------");}void init(){    getpri();    ans=0;    a[0]=0;    a[1]=0;    T[1].init(1);    for(int i=2;i<maxn;i++)    {        T[i].init(i);        bool f=1;        for(int j=0;j<(int)vec[i].size();j++)        {            int x = vec[i][j];            x=i/x;            if(f)            {                link(x,i);                ans+=x;                f=false;                //debug();            }            else            {                mroot(i);                access(x);                Splay(x);                //debug();                int MIN = T[T[x].ch[0]].MIN;                int u = T[T[x].ch[0]].u;                int v = T[T[x].ch[0]].v;                int GCD = T[x].MIN;                if(MIN>GCD)                {                    MIN=GCD;                    u=x;                    v=T[x].ch[0];                }                if(MIN<x)                {                    cut(u,v);                    link(x,i);                    ans-=MIN;                    ans+=x;                }            }        }        a[i]=ans;    }}int n;void solve(){    printf("%lld\n",a[n]);}int main(){    //double s = GetTickCount();    init();    //double e = GetTickCount();    //printf("%lf\n",e-s);    //freopen("5.txt","w",stdout);    //for(int i=1;i<maxn;i++)    //    printf("%d:%lld\n",i,a[i]);    while(~scanf("%d",&n)) solve();    return 0;}


原创粉丝点击