ACM-ICPC 2018 焦作赛区网络预赛 E 树链剖分 + 多重标记

You ye Jiu yuan is the daughter of the Great GOD Emancipator. And when she becomes an adult, she will be queen of Tusikur, so she wanted to travel the world while she was still young. In a country, she found a small pub called Whitehouse. Just as she was about to go in for a drink, the boss Carola appeared. And ask her to solve this problem or she will not be allowed to enter the pub. The problem description is as follows:

There is a tree with nn nodes, each node iicontains weight a[i]a[i], the initial value of a[i]a[i] is 00. The root number of the tree is 11. Now you need to do the following operations:

1)1) Multiply all weight on the path from uu to vvby xx

2)2) For all weight on the path from uu to vv, increasing xx to them

3)3) For all weight on the path from uu to vv, change them to the bitwise NOT of them

4)4) Ask the sum of the weight on the path from uu to vv

The answer modulo 2^{64}264.

Jiu Yuan is a clever girl, but she was not good at algorithm, so she hopes that you can help her solve this problem. Ding\backsim\backsim\backsim∽∽∽

The bitwise NOT is a unary operation that performs logical negation on each bit, forming the ones' complement of the given binary value. Bits that are 00 become 11, and those that are 11become 00. For example:

NOT 0111 (decimal 7) = 1000 (decimal 8)

NOT 10101011 = 01010100

Input

The input contains multiple groups of data.

For each group of data, the first line contains a number of nn, and the number of nodes.

The second line contains (n - 1)(n−1) integers b_ibi​, which means that the father node of node (i +1)(i+1) is b_ibi​.

The third line contains one integer mm, which means the number of operations,

The next mm lines contain the following four operations:

At first, we input one integer opt

1)1) If opt is 11, then input 33 integers, u, v, xu,v,x, which means multiply all weight on the path from uu to vv by xx

2)2) If opt is 22, then input 33 integers, u, v, xu,v,x, which means for all weight on the path from uuto vv, increasing xx to them

3)3) If opt is 33, then input 22 integers, u, vu,v, which means for all weight on the path from uu to vv, change them to the bitwise NOT of them

4)4) If opt is 44, then input 22 integers, u, vu,v, and ask the sum of the weights on the path from uuto vv

1 \le n,m,u,v \le 10^51≤n,m,u,v≤105

1 \le x < 2^{64}1≤x<264

Output

For each operation 44, output the answer.

样例输入复制

7
1 1 1 2 2 4
5
2 5 6 1
1 1 6 2
4 5 6
3 5 2
4 2 2
2
1
4
3 1 2
4 1 2
3 1 1
4 1 1

样例输出复制

5
18446744073709551613
18446744073709551614
0

题意:

给一颗树,每个节点初始化为0。m次操作,每次操作为下面四种之一:

1 u v w 将u到v的路径上的点的权值全部乘上w

2 u v w 将u到v的路径上的点的权值全部加上w

3 u v    将u到v的路径上的点的权值全部取反(~w)

4 u v    查询u到v的路径上所有节点的权值和

思路:树剖+多重标记。

取反是无法直接区间值取反的,因此化成乘法和加法形式。

~x = (2^64-1) - x

-x % (2^64) = (2^64-1)*x % (2^64) 

因此 ~x = (2^64-1)*x + (2^64-1)

这样就可以转化为加法和乘法了。(长知识了)

而且我们并不需要去快速乘,因为数值溢出时就是变为取模 2^64 的值。

代码:

#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define ll unsigned long long
using namespace std;
const int maxn=1e5+10;
const ll M=-1;
int num[maxn],n,head[maxn],tot,fa[maxn];
int siz[maxn],dep[maxn],size,top[maxn];
int cost[maxn];
int L,R,d;
ll sum[maxn*4],add[maxn*4],mul[maxn*4],k;
struct node
{
    int son,nxt;
}edge[maxn<<1];
void addedge(int x,int y)
{
    edge[tot].son=y;
    edge[tot].nxt=head[x];
    head[x]=tot++;
}
void dfs1(int x,int f)//求重儿子,深度,树大小等
{
    dep[x]=dep[f]+1;
    siz[x]=1;
    int p=0,wei=0;
    for(int i=head[x];~i;i=edge[i].nxt)
    {
        int son=edge[i].son;
        if(son==f) continue;
        fa[son]=x;
        dfs1(son,x);
        siz[x]+=siz[son];
        if(siz[son]>siz[wei]) wei=son,p=i;
    }
    if(p) swap(edge[head[x]].son,edge[p].son);
}
void dfs2(int x,int f)
{
    num[x]=++size;
    for(int i=head[x];~i;i=edge[i].nxt)
    {
        int son=edge[i].son;
        if(son==f) continue;
        if(i==head[x]) top[son]=top[x];
        else top[son]=son;
        dfs2(son,x);
    }
}
void pushdown(int l,int r,int rt)
{
    mul[rt<<1]=mul[rt<<1]*mul[rt];
    mul[rt<<1|1]=mul[rt<<1|1]*mul[rt];

    add[rt<<1]=add[rt<<1]*mul[rt]+add[rt];
    add[rt<<1|1]=add[rt<<1|1]*mul[rt]+add[rt];

    int mid=(l+r)>>1;
    sum[rt<<1]=sum[rt<<1]*mul[rt]+add[rt]*(mid-l+1);
    sum[rt<<1|1]=sum[rt<<1|1]*mul[rt]+add[rt]*(r-mid);

    mul[rt]=1;add[rt]=0;
}
void update(int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        if(d==1)
        {
            mul[rt]=mul[rt]*k;
            add[rt]=add[rt]*k;
            sum[rt]=sum[rt]*k;
        }else
        {
            add[rt]=add[rt]+k;
            sum[rt]=sum[rt]+k*(r-l+1);
        }
        return;
    }
    pushdown(l,r,rt);
    int mid=(l+r)>>1;
    if(L<=mid) update(lson);
    if(R>mid) update(rson);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
ll query(int l,int r,int rt)
{
    if(L<=l&&r<=R) return sum[rt];
    pushdown(l,r,rt);
    int mid=(l+r)>>1;
    ll ans=0;
    if(L<=mid) ans+=query(lson);
    if(R>mid) ans+=query(rson);
    return ans;
}
void build(int l,int r,int rt)
{
    sum[rt]=add[rt]=0;
    mul[rt]=1;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
}
void init()
{
    memset(head,-1,sizeof(head));
    size=tot=0;
    top[1]=1;
    build(1,n,1);
}
void mask(int x,int y,int s,ll &ans)
{
    int f1=top[x],f2=top[y];
    while(f1!=f2)  // log(n)刨链更新
    {
        if(dep[f1]>=dep[f2])
        {
            L=num[f1],R=num[x];
            x=fa[f1],f1=top[x];
        }
        else
        {
            L=num[f2],R=num[y];
            y=fa[f2],f2=top[y];
        }
        if(s) ans+=query(1,n,1);
        else update(1,n,1);
    }
    L=min(num[x],num[y]);
    R=max(num[x],num[y]);
    if(s) ans+=query(1,n,1);
    else update(1,n,1);
}
int main()
{
    while(~scanf("%d",&n))
    {
        init();
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&d);
            addedge(d,i);
            addedge(i,d);
        }
        dfs1(1,0);
        dfs2(1,0);
        int q,x,y;
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d",&d);
            ll ans=0;
            if(d==4)
            {
                scanf("%d%d",&x,&y);
                mask(x,y,1,ans);
                printf("%llu\n",ans);
            }
            else if(d==3)
            {
                scanf("%d%d",&x,&y);
                k=M;d=1;
                mask(x,y,0,ans);
                d=2,mask(x,y,0,ans);
            }
            else
            {
                scanf("%d%d%llu",&x,&y,&k);
                mask(x,y,0,ans);
            }
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值