zoukankan      html  css  js  c++  java
  • ACM-ICPC 2018 焦作赛区网络预赛 E. Jiu Yuan Wants to Eat ,树链抛分+线段树

    题目链接: E. Jiu Yuan Wants to Eat

    题意:给一颗树,四种操作,第一种把u到v最短路上的点都乘上x,第二种把u到v最短路上的点都加上x,第三种把u到v最短路上的点都取反,第四种求u到v最短路上的点的和。

    题解:标准的树抛然后用线段树维护,前两种都是线段树标准的修改操作,就是第三种不好搞得转换一下,~x=2^64-1-x;就可以取反转换成先乘-1在减1,然后就好做了。

    #include<bits/stdc++.h>
    #define ll long long
    #define ull unsigned long long
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    using namespace std;
    const int mod=1e9+7;
    int n;
    
    const int N = 1e5+100;
    int dep[N],fa[N],top[N],tid[N],son[N],siz[N],cn;
    int to[N*2],head[N*2],nxt[N*2];
    int cnt;
    struct edge
    {
        int u,v,w;
    }e[N];
    void add_edge(int u,int v)
    {
        to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
    }
    
    //树链抛分部分
    void dfs1(int u,int f,int d)//第一次dfs用来找重儿子,深度,子树大小,父亲,
    {
        fa[u]=f;dep[u]=d;siz[u]=1;
        for(int i=head[u];i;i=nxt[i])
        {
            if(to[i]!=f)
            {
                dfs1(to[i],u,d+1);siz[u]+=siz[to[i]];
                if(son[u]==-1||siz[to[i]]>siz[son[u]])son[u]=to[i];
            }
        }
    }
    void dfs2(int v,int tp)//得到重链的头节点,以及时间戳
    {
        top[v]=tp;
        tid[v]=++cn;
        if(son[v]==-1)return;
        dfs2(son[v],tp);
        for(int i=head[v];i;i=nxt[i])
        {
            if(to[i]!=fa[v]&&to[i]!=son[v])
            {
                dfs2(to[i],to[i]);
            }
        }
    }
    ull mul[N<<2],ad[N<<2],sum[N<<2];
    void init()
    {
        cnt=0;cn=0;
        memset(head,0,sizeof(head));
        memset(son,-1,sizeof(son));
    }
    void build(int l,int r,int rt){
        mul[rt] = 1;
        ad[rt] = 0;
        sum[rt] = 0;
        if(l == r) return ;
        int mid = l+r>>1;
        build(l,mid,rt<<1);
        build(mid+1,r,rt<<1|1);
    }
    void push_down(int rt,int l,int r)
    {
        if(mul[rt]!=1)
        {
            sum[rt<<1]*=mul[rt];
            ad[rt<<1]*=mul[rt];
            mul[rt<<1]*=mul[rt];
            sum[rt<<1|1]*=mul[rt];
            ad[rt<<1|1]*=mul[rt];
            mul[rt<<1|1]*=mul[rt];
            mul[rt]=1;
        }
        if(ad[rt])
        {
            int m=l+r>>1;
            sum[rt<<1]+=ad[rt]*(m-l+1);
            ad[rt<<1]+=ad[rt];
            sum[rt<<1|1]+=ad[rt]*(r-m);
            ad[rt<<1|1]+=ad[rt];
            ad[rt]=0;
        }
    }
    void push_up(int rt)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    void update1(int L,int R,ull val,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            sum[rt]*=val;
            ad[rt]*=val;
            mul[rt]*=val;
            return ;
        }
        push_down(rt,l,r);
        int m=l+r>>1;
        if(L<=m)update1(L,R,val,ls);
        if(R>m)update1(L,R,val,rs);
        push_up(rt);
    }
    void update2(int L,int R,ull val,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            sum[rt]+=val*(r-l+1);
            ad[rt]+=val;
            return ;
        }
        push_down(rt,l,r);
        int m=l+r>>1;
        if(L<=m)update2(L,R,val,ls);
        if(R>m)update2(L,R,val,rs);
        push_up(rt);
    }
    ull query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            return sum[rt];
        }
        push_down(rt,l,r);
        int m=l+r>>1;
        ull ans=0;
        if(L<=m)ans+=query(L,R,ls);
        if(R>m)ans+=query(L,R,rs);
        return ans;
    }
    void _mul(int x,int y,ull v)
    {
        int fx=top[x],fy=top[y];
        while(top[fx]!=top[fy])
        {
            if(dep[fx]>dep[fy]) update1(tid[fx],tid[x],v,1,n,1),x=fa[fx];
            else update1(tid[fy],tid[y],v,1,n,1),y=fa[fy];
            fx=top[x];fy=top[y];
        }
        if(dep[x]<dep[y])swap(x,y);
        update1(tid[y],tid[x],v,1,n,1);
    }
    void _add(int x,int y,ull v)
    {
        int fx=top[x],fy=top[y];
        while(top[fx]!=top[fy])
        {
            if(dep[fx]>dep[fy]) update2(tid[fx],tid[x],v,1,n,1),x=fa[fx];
            else update2(tid[fy],tid[y],v,1,n,1),y=fa[fy];
            fx=top[x];fy=top[y];
        }
        if(dep[x]<dep[y])swap(x,y);
        update2(tid[y],tid[x],v,1,n,1);
    }
    ull query_sum(int x,int y)
    {
        ull ans=0;
        int fx=top[x],fy=top[y];
        while(top[fx]!=top[fy])
        {
    
            if(dep[fx]>dep[fy]) ans+=query(tid[fx],tid[x],1,n,1),x=fa[fx];
            else ans+=query(tid[fy],tid[y],1,n,1),y=fa[fy];
            fx=top[x];fy=top[y];
        }
        if(dep[x]<dep[y])swap(x,y);
        ans+=query(tid[y],tid[x],1,n,1);
        return ans;
    }
    int main()
    {
        while(scanf("%d",&n)==1)
        {
            init();
            for(int i=2;i<=n;i++)
            {
                int x;
                scanf("%d",&x);
                add_edge(x,i);
                add_edge(i,x);
            }
            dfs1(1,0,0);
            dfs2(1,1);
            build(1,n,1);
            int m;
            scanf("%d",&m);
            for(int i = 1;i <= m;i ++){
                int op,x,y;
                ull z;
                scanf("%d %d %d",&op,&x,&y);
                if(op == 1){
                    scanf("%llu",&z);
                    _mul(x,y,z);
                }
                else if(op == 2){
                    scanf("%llu",&z);
                    _add(x,y,z);
                }
                else if(op == 3){
                    _mul(x,y,-1);
                    _add(x,y,-1);
                }
                else{
                    printf("%llu
    ",query_sum(x,y));
                }
            }
    
        }
    }
  • 相关阅读:
    Win7 64位下ProxyCap代理Java
    kafka一个诡异错误
    linux下oracle修改、新建用户并授权
    es常用查询
    linux 下启动tomcat报错 Cannot find ./catalina.sh
    linux虚拟机添加端口访问
    Linux下启动Oracle服务和监听程序
    es基础
    mysql授权远程任意人登录
    添加POI导出excel通用工具类
  • 原文地址:https://www.cnblogs.com/lhclqslove/p/9675176.html
Copyright © 2011-2022 走看看