【动态树X脑残错误】hdu5002

本文深入探讨了一种复杂但实用的数据结构——动态树,并通过代码示例详细解释了其构建及维护过程。文章针对动态树中节点插入、删除、查询等操作进行了详尽的说明,并特别强调了标记传递和下放的重要性。

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

一个挺简单的一个动态树,结果多写了一个标记,导致代码量大幅度增加,再加上一个脑残错误...

本来以为多updata几次至少不会错,结果在一个地方updata之前还存有标记...

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <algorithm>
const int oo=1073741819;
using namespace std;
struct PP{
    int p,k;
};
int n,m,ss;
int tail[500000],next[1000000],sora[1000000];
int l[500000],r[500000],rt[500000];
int sw[500000],t[500000][2],Max[500000][2],sum[500000][2],w[500000],size[500000];
void modify_add(int x,int p)
{
    if (!x) return ;
    if (t[x][0]>-oo) {
        t[x][0]+=p,t[x][1]=-oo;
        if (Max[x][0]>-oo) Max[x][0]+=p;
        if (Max[x][1]>-oo) Max[x][1]+=p;
        w[x]+=p;
        return ;
    }
    t[x][0]=-oo;
    if (t[x][1]>-oo) t[x][1]+=p;
    else t[x][1]=p;
    if (Max[x][0]>-oo) Max[x][0]+=p;
    if (Max[x][1]>-oo) Max[x][1]+=p;
    w[x]+=p;
}
void modify_fuzhi(int x,int p)
{
    if (!x) return ;
    t[x][0]=p,t[x][1]=-oo;
    Max[x][0]=p,sum[x][0]=size[x];
    Max[x][1]=-oo,sum[x][1]=0;
    w[x]=p;
}
void swap(int x)
{
    if (!x) return ;
    swap(l[x],r[x]);
    sw[x]^=1;
}
void merge(PP A[],int P,int K)
{
    for (int i=0;i<=1;i++)
        if (A[i].p==P) {
            A[i].k+=K;
            return ;
        }
    if (P>A[0].p) {
        A[1]=A[0];
        A[0].p=P,A[0].k=K;
    }
    else if (P>A[1].p) {
        A[1].p=P,A[1].k=K;
    }
}
void updata(int x)
{
    if (!x) return ;
    //if (sw[x] || t[x][0]>-oo || t[x][1]>-oo) return ;
    PP ans[2];
    ans[0].p=ans[1].p=-oo;
    ans[0].k=ans[1].k=0;
    merge(ans,w[x],1);
    for (int i=0;i<=1;i++) {
        if (l[x]) merge(ans,Max[l[x]][i],sum[l[x]][i]);
        if (r[x]) merge(ans,Max[r[x]][i],sum[r[x]][i]);
    }
    Max[x][0]=ans[0].p,sum[x][0]=ans[0].k;
    Max[x][1]=ans[1].p,sum[x][1]=ans[1].k;
    size[x]=size[l[x]]+size[r[x]]+1;
}
void pushdown(int x)
{
    if (!x) return ;
    if (sw[x]) {
        swap(l[x]),swap(r[x]);
        sw[x]=0;
    }
    if (t[x][0]>-oo) {
        modify_fuzhi(l[x],t[x][0]);
        modify_fuzhi(r[x],t[x][0]);
        t[x][0]=-oo;
    }
    if (t[x][1]>-oo) {
        modify_add(l[x],t[x][1]);
        modify_add(r[x],t[x][1]);
        t[x][1]=-oo;
    }
    updata(x);
}
void right(int x)
{
    int y=rt[x],z=rt[y];
    l[y]=r[x],rt[r[x]]=y;
    r[x]=y,rt[y]=x;
    if (l[z]==y) l[z]=x;else if (r[z]==y) r[z]=x;
    rt[x]=z;
    updata(y);
}
void left(int x)
{
    int y=rt[x],z=rt[y];
    r[y]=l[x],rt[l[x]]=y;
    l[x]=y,rt[y]=x;
    if (l[z]==y) l[z]=x;else if (r[z]==y) r[z]=x;
    rt[x]=z;
    updata(y);
}
void splay(int x)
{
    pushdown(x);
    for (int y,z;l[rt[x]]==x || r[rt[x]]==x;) {
        y=rt[x],z=rt[y];
        if (l[z]==y || r[z]==y) pushdown(z);
        pushdown(y),pushdown(x);
        if (l[y]==x) {
            if (l[z]==y) right(y);
            right(x);
        }
        else if (r[y]==x) {
            if (r[z]==y) left(y);
            left(x);
        }
    }
    updata(x);
}
void access(int x)
{
    splay(x);
    l[x]=0,updata(x);
    for (;rt[x];) {
        int y=rt[x];
        splay(y);
        l[y]=x,updata(y);
        splay(x);
    }
}
void origin()
{
    ss=n;
    for (int i=1;i<=n;i++) tail[i]=i,next[i]=0;
    for (int i=1;i<=n;i++) {
        sw[i]=0;
        t[i][0]=t[i][1]=-oo;
        Max[i][0]=Max[i][1]=-oo;
        sum[i][0]=sum[i][1]=0,rt[i]=0;
        Max[i][0]=w[i];
        sum[i][0]=1;
        size[i]=1;
        l[i]=r[i]=0;
    }
}
void link(int x,int y)
{
    ++ss,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y,next[ss]=0;
    ++ss,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x,next[ss]=0;
}
void dfs(int x,int y)
{
    for (int i=x,ne;next[i];) {
        i=next[i],ne=sora[i];
        if (ne!=y) rt[ne]=x,dfs(ne,x);
    }
}
int ask(int x,int y)
{
    access(x),access(y);
    splay(x);
    if (rt[x]) return rt[x];
    return x;
}
void Del(int x,int y)
{
    int lca=ask(x,y);
    if (lca==x) swap(x,y);
    access(y);
    splay(x),splay(y);
    rt[x]=0;
    updata(x),updata(y);			//updata前标记没有下放 
}
void Link(int x,int y)
{
    access(x);
    splay(x),splay(y);
    swap(x);
    rt[x]=y;
    updata(x),updata(y);			//updata前标记没有下放
}
int main()
{
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
    int T;
    scanf("%d",&T);
    for (int test=1;T;T--,test++) {
        printf("Case #%d:\n",test);
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) 
            scanf("%d",&w[i]);
        origin();
        for (int i=1;i<=n-1;i++) {
            int x,y;
            scanf("%d%d",&x,&y);
            link(x,y);
        }
        dfs(1,0);
        for (int i=1;i<=m;i++) {
            int c;
            scanf("%d",&c);
            if (1==c) {
                int x,y,a,b;
                scanf("%d%d%d%d",&x,&y,&a,&b);
                if (x!=y) Del(x,y);
                if (a!=b) Link(a,b);
            }
            else if (2==c) {
                int a,b,x;
                scanf("%d%d%d",&a,&b,&x);
                if (a==b) {
                    splay(a);
                    pushdown(a);
                    w[a]=x;
                    updata(a);
                    continue;
                }
                int lca=ask(a,b);
                if (lca==a) swap(a,b);
                if (lca==b) {
                    access(a),access(b);
                    splay(a);
                    modify_fuzhi(a,x);
                    splay(b);
                    pushdown(b);
                    w[b]=x;
                    updata(b);
                }
                else {
                    access(a),access(b),access(lca);
                    splay(a),modify_fuzhi(a,x);
                    splay(b),modify_fuzhi(b,x);
                    splay(lca);
                    pushdown(lca);
                    w[lca]=x;
                    updata(lca);
                }
            }
            else if (3==c) {
                int a,b,x;
                scanf("%d%d%d",&a,&b,&x);
                if (a==b) {
                    splay(a);
                    pushdown(a);
                    w[a]+=x;
                    updata(a);
                    continue;
                }
                int lca=ask(a,b);
                if (lca==a) swap(a,b);
                if (lca==b) {
                    access(a),access(b);
                    splay(a);
                    modify_add(a,x);
                    splay(b);
                    pushdown(b);
                    w[b]+=x;
                    updata(b);
                }
                else {
                    access(a),access(b),access(lca);
                    splay(a),modify_add(a,x);
                    splay(b),modify_add(b,x);
                    splay(lca);
                    pushdown(lca);
                    w[lca]+=x;
                    updata(lca);
                }
            }
            else if (4==c) {
                int a,b;
                scanf("%d%d",&a,&b);
                if (a==b) {
                    printf("ALL SAME\n");
                    continue;
                }
                PP ans[2];
                ans[0].p=ans[1].p=-oo;
                ans[0].k=ans[1].k=0;                
                int lca=ask(a,b);
                if (lca==a) swap(a,b);
                if (lca==b) {
                    access(a),access(b);
                    splay(a);
                    merge(ans,Max[a][0],sum[a][0]);
                    merge(ans,Max[a][1],sum[a][1]);
                    splay(b);
                    merge(ans,w[b],1);
                }
                else {
                    access(a),access(b),access(lca);
                    splay(a),splay(b);
                    merge(ans,Max[a][0],sum[a][0]),merge(ans,Max[a][1],sum[a][1]);
                    merge(ans,Max[b][0],sum[b][0]),merge(ans,Max[b][1],sum[b][1]);
                    splay(lca);
                    merge(ans,w[lca],1);
                }
                if (!ans[1].k) printf("ALL SAME\n");
                else printf("%d %d\n",ans[1].p,ans[1].k);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值