Codeforces 176E

本文介绍了一种高效的数据结构——树链剖分,用于处理基于树结构的查询和更新操作。通过预处理得到每个节点的最近公共祖先(LCA),可以快速解答涉及路径最短距离的问题。此外,文章提供了详细的C++实现代码,并展示了如何利用线段树进行区间更新和查询。

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

树链剖分
增加一个或删除一个点
1.如果有其他路径经过它,它就对答案没有影响
2.其他情况就各种找lca
反正我已经看不懂我的代码了,就酱

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef __int64 LL;
const int N=1e5+100;
const int INF=0x3f3f3f3f;
#define ll o<<1
#define rr o<<1|1
#define mid (l+r)/2
struct Edge {
    int v,next,w;
    Edge(){}
    Edge(int v,int next,int w):v(v),next(next),w(w){}
}e[N*2];
int head[N],total;
void init(){
    memset(head,-1,sizeof(head));total=0;
}
void adde(int u,int v,int w){
    e[total]=Edge(v,head[u],w);head[u]=total++;
}

int dep[N],sz[N],fa[N],son[N];
int st[N],ed[N],ti,fst[N];LL dis[N];

void getson(int u,int f){///�ض���
    //printf("getson %d %d\n",u,f);
    dep[u]=dep[f]+1;sz[u]=1;fa[u]=f;son[u]=-1;
    st[u]=++ti;fst[ti]=u;
    for(int i=head[u];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(v==f)continue;
        dis[v]=dis[u]+e[i].w;
        getson(v,u);
        sz[u]+=sz[v];
        if(son[u]==-1||sz[son[u]]<sz[v])son[u]=v;
    }
    ed[u]=ti;
}

int top[N],p[N],fp[N],pos;
void getpos(int u,int clo){////������p������
    top[u]=clo;
    p[u]=++pos;
    fp[pos]=u;
    if(son[u]==-1)return ;
    getpos(son[u],clo);
    for(int i=head[u];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(v!=son[u]&&v!=fa[u]){
            getpos(v,v);
        }
    }
}
////////seg_tree;
int mx[N<<2],add[N<<2];
void pushdown(int l,int r,int o){
    if(add[o]){
        add[ll]+=add[o];
        add[rr]+=add[o];
        mx[ll]+=add[o];
        mx[rr]+=add[o];
        add[o]=0;
    }
}
void pushup(int l,int r,int o){
    mx[o]=max(mx[ll],mx[rr]);
}
int L,R,V,opx;
void update(int l,int r,int o){
    //printf("update%d %dLR,%d %dlr,%d %dVopx\n",L,R,l,r,V,opx);
    if(L<=l&&r<=R){
        add[o]+=V;
        mx[o]+=V;
        return ;
    }
    pushdown(l,r,o);
    if(L<=mid)update(l,mid,ll);
    if(R>mid)update(mid+1,r,rr);
    pushup(l,r,o);
}
int query(int l,int r,int o){
    //printf("query%d %dLR,%d %d %d %d\n",L,R,l,r,V,opx);
    if(l==r){
        if(V==-1)return mx[o];
        else if(mx[o]>=V)return l;
        else return opx;
    }
    if(L<=l&&r<=R){
        if(V==-1)return mx[o];
        else if(opx==-1){
            pushdown(l,r,o);
            if(mx[rr]>=V) return query(mid+1,r,rr);
            else if(mx[ll]>=V) return query(l,mid,ll);
            else return -1;
        }
        else {
            pushdown(l,r,o);
            if(mx[ll]>=V)return query(l,mid,ll);
            else if(mx[rr]>=V)return query(mid+1,r,rr);
            else return opx;
        }
    }
    pushdown(l,r,o);
    int ans=opx;
    if(V==-1){
        if(L<=mid)ans=max(ans,query(l,mid,ll));
        if(R>mid)ans=max(ans,query(mid+1,r,rr));
    }
    else if(opx==-1){
        if(R>mid)ans=max(ans,query(mid+1,r,rr));
        if(ans==-1&&L<=mid)ans=max(ans,query(l,mid,ll));
    }
    else {
        if(L<=mid)ans=min(ans,query(l,mid,ll));
        if(ans==INF&&R>mid)ans=min(ans,query(mid+1,r,rr));
    }
    return ans;
}

int lca(int u,int v,int op,int vx){
    int fu=top[u],fv=top[v];
    int ans=vx;
    //printf("%d %dufu,%d %dfv,%dop %dvx\n",u,fu,v,fv,op,vx);
    while(fu!=fv){
        if(op==-2){
            L=p[fu],R=p[u],V=vx,opx=vx;update(1,pos,1);
        }
        else if(op==-1){
            L=p[fu],R=p[u],V=-1,opx=vx;ans=max(ans,query(1,pos,1));
        }
        else{
            L=p[fu],R=p[u],V=op,opx=vx;
            if(opx==-1){
                ans=query(1,pos,1);
                if(ans!=-1)return fp[ans];
            }
            else {
                ans=min(ans,query(1,pos,1));
            }
        }
        u=fa[fu];fu=top[u];
    }
    swap(u,v);
    if(op==-2){//////// change
        L=p[u],R=p[v],V=vx,opx=vx;update(1,pos,1);
    }
    else if(op==-1){ ///////// query max
        L=p[u],R=p[v],V=-1,opx=vx;
        ans=max(ans,query(1,pos,1));
    }
    else {     ///////// query >=op id
        L=p[u],R=p[v],V=op,opx=vx;
        if(opx==-1){
            ans=max(ans,query(1,pos,1));
            //printf("%dans\n",ans);
            if(ans!=-1)ans=fp[ans];
        }
        else {
            ans=min(ans,query(1,pos,1));
            if(ans!=INF)ans=fp[ans];
        }
    }
    return ans;
}


void solve(){
    pos=0;
    dep[0]=0;
    dis[1]=0;ti=0;/////////
    getson(1,0);
    getpos(1,1);
}

int cc[N<<2];
void ucc(int l,int r,int o,int x,int op){
    if(l==r){
        if(op==1)cc[o]=x;
        else cc[o]=INF;
        return ;
    }
    if(x<=mid)ucc(l,mid,ll,x,op);
    else ucc(mid+1,r,rr,x,op);
    cc[o]=min(cc[ll],cc[rr]);
}

int qcc(int l,int r,int o){
    //printf("%d %dlr%d %dLR\n",l,r,L,R);
    if(L<=l&&r<=R){
        return cc[o];
    }
    int ans=INF;
    if(L<=mid)ans=qcc(l,mid,ll);
    if(ans==INF&&R>mid)ans=qcc(mid+1,r,rr);
    return ans;
}

int main(){
    #ifdef DouBi
    freopen("in.cpp","r",stdin);
    //freopen("out.cpp","w",stdout);
    #endif // DouBi
    int n;
    while(scanf("%d",&n)!=EOF){
        init();
        for(int i=1;i<n;i++){
            int a,b,c;scanf("%d%d%d",&a,&b,&c);
            adde(a,b,c);adde(b,a,c);
        }
        solve();
        //printf("sovle\n");
        memset(cc,0x3f,sizeof(cc));
        //printf("%d %d\n",cc[1],INF);
        memset(add,0,sizeof(add));
        memset(mx,0,sizeof(mx));
        //for(int i=1;i<=n;i++)printf("%I64d %d %d\n",dis[i],son[i],fa[i]);
        //for(int i=1;i<=n;i++)printf("st%d ed%d\n",st[i],ed[i]);printf("%dti\n",ti);
        int q;scanf("%d",&q);
        LL sum=0;
        lca(1,1,-2,1);
        int num=0;
        while(q--){
            char op[10];int x;
            scanf("%s",op);
            if(n==1){
                if(op[0]=='?')printf("0\n");
                else scanf("%d",&x);
                continue;
            }
            if(op[0]=='?'){
                int xx=lca(1,1,-1,-1);
                if(xx>=3)printf("%I64d\n",sum);
                else if(xx==1)printf("0\n");
                else {
                    x=1;
                    lca(x,x,-2,-1);
                    ////////
                    L=st[x]+1,R=ed[x];
                    int z1=qcc(1,ti,1);
                    if(z1==INF){
                        printf("0\n");
                    }
                    else {
                        LL zz;
                        int y1=lca(fst[z1],1,-1,-1);
                        if(y1>=2){
                            int id=lca(fst[z1],1,2,INF);
                            zz=dis[id];
                        }
                        else {
                            zz=dis[fst[z1]];
                        }
                        printf("%I64d\n",sum-zz);
                    }
                    lca(x,x,-2,1);
                }
            }
            else {
                scanf("%d",&x);
                if(op[0]=='+'){
                    num++;
                    if(x==1){
                        lca(x,x,-2,1);
                    }
                    else {
                        int y=lca(x,x,-1,-1);
                        if(y>=1){
                            lca(x,x,-2,1);
                        }
                        else {
                            int id=lca(fa[x],1,1,-1);
                            lca(x,id,-2,1);
                            sum+=dis[x]-dis[id];
                        }
                    }
                    ucc(1,ti,1,st[x],1);
                }
                else {
                    num--;
                    if(x==1){
                        lca(x,x,-2,-1);
                    }
                    else {
                        int y=lca(x,x,-1,-1);
                        if(y>=2){
                            lca(x,x,-2,-1);
                        }
                        else {
                            int id=lca(fa[x],1,2,-1);
                            lca(x,id,-2,-1);
                            sum-=dis[x]-dis[id];
                        }
                    }
                    ucc(1,ti,1,st[x],-1);
                }
            }
//            for(int i=1;i<=n;i++){
//                int xx=lca(i,i,-1,-1);
//                printf("%d:%d ",i,xx);
//            }printf("\n");
//            printf("%s %d .........\n",op,op[0]=='?'?-1:x);

        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值