zoukankan      html  css  js  c++  java
  • 【Luogu】P3313旅行(树链剖分)

      题目链接

      动态开点的树链剖分qwq。

      跟小奇的花园一模一样,不做过多讲解。

      

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<cstdlib>
    #include<algorithm>
    #define maxn 100010
    #define mid ((l+r)>>1)
    #define check(x) if(x==0)    x=++tot;
    using namespace std;
    inline long long read(){
        long long num=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            num=num*10+ch-'0';
            ch=getchar();
        }
        return num*f;
    }
    
    struct Edge{
        int next,to;
    }edge[maxn*3];
    int head[maxn],num;
    inline void add(int from,int to){
        edge[++num]=(Edge){head[from],to};
        head[from]=num;
    }
    
    int dfn[maxn];
    int back[maxn],cnt;
    int sum[maxn*100],tot;
    int mav[maxn*100];
    int root[maxn];
    int ls[maxn*100];
    int rs[maxn*100];
    int top[maxn];
    int size[maxn];
    int son[maxn];
    int deep[maxn];
    int father[maxn];
    int d[maxn];
    int q[maxn];
    int n,m;
    
    void find(int x,int fa){
        size[x]=1;deep[x]=deep[fa]+1;
        for(int i=head[x];i;i=edge[i].next){
            int to=edge[i].to;
            if(to==fa)    continue;
            father[to]=x;
            find(to,x);
            size[x]+=size[to];
            if(son[x]==0||size[son[x]]<size[to])    son[x]=to;
        }
    }
    
    void unionn(int x,int Top){
        dfn[x]=++cnt;    back[cnt]=x;
        top[x]=Top;
        if(son[x]==0)    return;
        unionn(son[x],Top);
        for(int i=head[x];i;i=edge[i].next){
            int to=edge[i].to;
            if(to==father[x]||to==son[x])    continue;
            unionn(to,to);
        }
    }
    
    inline void pushup(int rt){
        sum[rt]=sum[ls[rt]]+sum[rs[rt]];
        mav[rt]=max(mav[ls[rt]],mav[rs[rt]]);
    }
    
    void update(int o,int num,int l,int r,int &rt){
        check(rt);
        if(l==r){
            sum[rt]=num;
            mav[rt]=num;
            return;
        }
        if(o<=mid)    update(o,num,l,mid,ls[rt]);
        else        update(o,num,mid+1,r,rs[rt]);
        pushup(rt);
        return;
    }
    
    int quemax(int from,int to,int l,int r,int &rt){
        if(rt==0)    return 0;
        if(from<=l&&to>=r)    return mav[rt];
        int ans=0;
        if(from<=mid)    ans=max(ans,quemax(from,to,l,mid,ls[rt]));
        if(to>mid)        ans=max(ans,quemax(from,to,mid+1,r,rs[rt]));
        return ans;
    }
    
    int quesum(int from,int to,int l,int r,int &rt){
        if(rt==0)    return 0;
        if(from<=l&&to>=r)    return sum[rt];
        int ans=0;
        if(from<=mid)    ans+=quesum(from,to,l,mid,ls[rt]);
        if(to>mid)        ans+=quesum(from,to,mid+1,r,rs[rt]);
        return ans;
    }
    
    int askmax(int from,int to,int val){
        int ans=0;
        while(top[from]!=top[to]){
            if(deep[top[from]]<deep[top[to]])    swap(from,to);
            ans=max(ans,quemax(dfn[top[from]],dfn[from],1,n,root[val]));
            from=father[top[from]];
        }
        if(deep[from]>=deep[to])    swap(from,to);
        ans=max(ans,quemax(dfn[from],dfn[to],1,n,root[val]));
        return ans;
    }
    
    int asksum(int from,int to,int val){
        int ans=0;
        while(top[from]!=top[to]){
            if(deep[top[from]]<deep[top[to]])    swap(from,to);
            ans+=quesum(dfn[top[from]],dfn[from],1,n,root[val]);
            from=father[top[from]];
        }
        if(deep[from]>=deep[to])    swap(from,to);
        ans+=quesum(dfn[from],dfn[to],1,n,root[val]);
        return ans;
    }
    
    void chancol(int pos,int val){
        update(dfn[pos],0,1,n,root[q[pos]]);
        update(dfn[pos],d[pos],1,n,root[val]);
        q[pos]=val;
    }
    
    void channum(int pos,int val){
        update(dfn[pos],val,1,n,root[q[pos]]);
        d[pos]=val;
    }
    
    int main(){
        n=read(),m=read();
        for(int i=1;i<=n;++i){
            d[i]=read();q[i]=read();
        }
        for(int i=1;i<n;++i){
            int x=read(),y=read();
            add(x,y);
            add(y,x);
        }
        find(1,1);
        unionn(1,1);
        for(int i=1;i<=n;++i)    update(dfn[i],d[i],1,n,root[q[i]]);
        for(int i=1;i<=m;++i){
            char c[10];
            scanf("%s",c);
            if(c[0]=='C'){
                if(c[1]=='C'){
                    int x=read(),y=read();
                    chancol(x,y);
                }
                else{
                    int x=read(),y=read();
                    channum(x,y);
                }
            }
            else if(c[0]=='Q'){
                if(c[1]=='S'){
                    int x=read(),y=read();
                    printf("%d
    ",asksum(x,y,q[x]));
                }
                else{
                    int x=read(),y=read();
                    printf("%d
    ",askmax(x,y,q[x]));
                }
            }
        }
        return 0;
    }

    https://www.luogu.org/problemnew/show/P3313

  • 相关阅读:
    Asp.Net 获取客户端真实IP方法总结
    C# 中英文符号互转(半角全角互转)
    执行git commit命令提示: “Please tell me who you are”的解决方案
    Tools
    VSC
    DevOps
    VSC
    DevOps
    DevOps
    K8S
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/8352808.html
Copyright © 2011-2022 走看看