树链剖分

本文深入探讨了树链剖分算法的实现细节,通过具体的代码示例展示了如何进行轻重边划分、路径压缩等关键步骤,并介绍了如何利用数据结构优化查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

赤裸裸的树链剖分,结果划分轻重边时以为同一条链的重边相邻。。。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
struct line
{
    int x,y,z;
}p[30005];
int rt[10005],ro[10005],q[10005],g[10005],d[10005],w[10005],b[65536],u[10005],tail[10005],next[30005],sora[30005],cost[30005],v[10005],c[10005];
int power[30005],o[10005],l[10005],r[10005],a[15];
int f[50000][15];
int n,m,tot,t,tt,m1,ans,ss;
void dfs(int x,int y,int dep,int bj)
{
    int i,ne,cos;
    rt[x]=y;ro[x]=bj;q[bj]=x;g[x]=1;
    f[++tot][0]=x;
    d[x]=dep;u[x]=tot;
    int maxg=0,maxi=0,maxb=0;
    for (i=x;next[i]!=0;)
    {
        i=next[i];ne=sora[i];
        if (ne!=y)
        {
            dfs(ne,x,dep+1,power[i]);
            f[++tot][0]=x;
            g[x]+=g[ne];
            if (g[ne]>maxg)           
            {
                maxg=g[ne];maxi=ne;maxb=cost[i];
            }
        }
    }
    if (0==maxg) return ;
    ne=maxi;cos=maxb;
    if (v[ne])
    {
        w[ne]=cos;
        v[x]=v[ne];
    }
    else 
    {
        w[ne]=cos;
        ++t;
        v[x]=t,v[ne]=t;
    }
}
int min(int x,int y)
{
    return (d[x]<d[y]) ? x : y;
}
int max(int x,int y)
{
    return (w[x]>w[y]) ? x : y;
}
void change(int x,int ww)
{
    w[x]=ww;
    x=(o[x]+m1)>>1;
    for (;x;x>>=1) b[x]=max(b[x<<1],b[(x<<1)+1]);
}
int cmp(const void*i,const void*j)
{
    int p=*(int *)i,q=*(int *)j;
    if (v[p]!=v[q]) return v[p] - v[q];
    return  -(d[p]-d[q]);
}
void ori()
{
    int k,i,j;
    k=(int)floor(log2(tot));
    a[0]=1;
    for (i=1;i<=k;i++) a[i]=a[i-1]<<1;
    for (i=1;i<=k;i++)
        for (j=1;j<=tot;j++)
            if (j+a[i]-1<=tot)
                f[j][i]=min(f[j][i-1],f[j+a[i-1]][i-1]);
            else break;
    for (i=1;i<=n;i++) c[i]=i;
    qsort(c+1,n,sizeof(c[1]),cmp);
    for (i=1;i<=n;i++)  
        if (v[c[i]])  
        {
            r[v[c[i]]]=i;
            o[c[i]]=i;
            b[i+m1]=c[i];
            change(c[i],w[c[i]]); 
        }
}
int lca(int x,int y)
{
    int e;
    if (x>y) {e=x;x=y;y=e;}
    int ans=0,k;
    k=(int)floor(log2(y-x+1));
    ans=min(f[x][k],f[y-a[k]+1][k]);
    return ans;
}
int ask(int l,int r)
{
    int ans=0;
    l=l+m1-1,r=r+m1+1;
    for (;!(1==(l^r));l>>=1,r>>=1)
    {
        if (0==(l&1)) if (w[b[l+1]]>ans) ans=w[b[l+1]];
        if (1==(r&1)) if (w[b[r-1]]>ans) ans=w[b[r-1]];
    }
    return ans;
}
void make(int x,int ari)
{
    int ll,rr,cos;
    for (;x!=ari;)
    {
        if (v[x])
        {
            ll=o[x];
            if (v[x]!=v[ari]) rr=r[v[x]]-1;
            else rr=o[ari]-1;
            cos=ask(ll,rr);
            if (cos>ans) ans=cos;
            if (v[x]==v[ari]) x=b[rr+m1];else x=b[rr+m1+1];
            if (p[ro[x]].z>ans) ans=p[ro[x]].z;
            x=rt[x];
        }
        else 
        {
            if (p[ro[x]].z>ans) ans=p[ro[x]].z;
            x=rt[x];
        }
    }
}
void origin()
{
    int i;
    m1=1;
    for (;m1<=n+2;m1<<=1) ;
    ss=n;
    for (i=1;i<=n;i++) tail[i]=i;
}
void link(int x,int y,int z,int i)
{
    ss++;next[tail[x]]=ss;tail[x]=ss;sora[ss]=y;cost[ss]=z;power[ss]=i;
}
void init()
{
    int i,x,y,z,lcr;
    char ch;
    scanf("%d\n",&n);
    origin();    
    for (i=1;i<=n-1;i++)
    {
        scanf("%d%d%d\n",&x,&y,&z);
        link(x,y,z,i);link(y,x,z,i);
        p[i].x=x,p[i].y=y,p[i].z=z;
    }
    t=0;tt=0;tot=0;
    memset(d,127,sizeof(d));
    dfs(1,0,1,0);
    ori();
    scanf("%d\n",&m);
    for (i=1;i<=m;i++)
    {
        scanf("%c",&ch);
        if ('Q'==ch)
        {
            scanf("%d%d\n",&x,&y);
            ans=0,lcr=lca(u[x],u[y]);
            make(x,lcr);
            make(y,lcr);
            printf("%d\n",ans);   
        }
        else 
        {
            scanf("%d%d\n",&x,&y);
            p[x].z=y;
            if (v[q[x]]) change(q[x],y);
        }
    }
}
int main()
{
    freopen("road.in","r",stdin);
    freopen("road.out","w",stdout);
        init();
    return 0;    
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值