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\n",query_sum(x,y));
            }
        }

    }
}

 

posted @ 2018-09-19 16:16  lhclqslove  阅读(133)  评论(0编辑  收藏  举报