2018焦作网络赛-E- Jiu Yuan Wants to Eat

题目描述

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 n nodes, each node i contains weight a[i], the initial value of a[i] is 0.  The root number of the tree is 1. Now you need to do the following operations:
1) Multiply all weight on the path from u to v by x
2) For all weight on the path from u to v, increasing x to them
3) For all weight on the path from u to v, change them to the bitwise NOT of them
4) Ask the sum of the weight on the path from u to v
The answer modulo 2^64.

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~~~

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 0 become 1, and those that are 1 become 0. For example:

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

输入

The input contains multiple groups of data.
For each group of data, the first line contains a number of n, and the number of nodes.
The second line contains (n - 1) integers bi, which means that the father node of node (i +1) is bi.
The third line contains one integer m, which means the number of operations,
The next m lines contain the following four operations:
At first, we input one integer opt
1) If opt is 1, then input 3 integers, u, v, x, which means multiply all weight on the path from u to v by x
2) If opt is 2, then input 3 integers, u, v, x, which means for all weight on the path from u to v, increasing x to them
3) If opt is 3, then input 2 integers, u, v, which means for all weight on the path from u to v, change them to the bitwise NOT of them
4) If opt is 4, then input 2 integers, u, v, and ask the sum of the weights on the path from u to v

1 ≤ n, m, u, v ≤ 10^5
1 ≤ x < 2^64

输出

For each operation 4, 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
题意
给一棵n个节点的有根树,每个节点有权值,初始是0,m次操作
1 u v x:给u v路径上的点权值*x
2 u v x:给u v路径上的点权值+x
3 u v:给u v路径上的点权值取反
4 u v:询问u v路径上的权值和,对2^64取模

树链剖分:https://wenku.baidu.com/view/a088de01eff9aef8941e06c3.html

然后如果没有取反操作,线段树维护和sum,加法标记add和乘法标记mul即可
对于取反操作,因为是对2^64取模的,即x+(!x)=2^64-1,所以x=(2^64-1)-x,因此取反就变成乘法和加法了:!x=(-1)*x+(-1) (-1对于2^64取模后是(2^64-1))

#include <bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int N=1e5+100;
int n,m,tot,cnt;
int fa[N],last[N];
int son[N],deep[N],dfn[N],num[N],top[N];//重儿子 深度 dfs序 子树规模 所在重链的顶端节点
ull sum[N*4],add[N*4],mul[N*4];
struct orz{
    int v,nex;}e[N];
void init()
{
    cnt=0;
    tot=0;
    memset(last,0,sizeof(last));
    memset(son,-1,sizeof(son));
}
void Inses(int x,int y)
{
    cnt++;
    e[cnt].v=y;
    e[cnt].nex=last[x];
    last[x]=cnt;
}
void dfs1(int x,int d)
{
    deep[x]=d;
    num[x]=1;
    for (int i=last[x];i;i=e[i].nex)
    {
        int v=e[i].v;
        dfs1(v,d+1);
        num[x]+=num[v];
        if (son[x]==-1 || num[v]>num[son[x]]) son[x]=v;
    }
}
void dfs2(int x,int sp)
{
    top[x]=sp;
    dfn[x]=++tot;
    if (son[x]==-1) return ;
    dfs2(son[x],sp);
    for (int i=last[x];i;i=e[i].nex)
    {
        int v=e[i].v;
        if (v!=son[x]) dfs2(v,v);
    }
}
void PushUp(int s)
{
    sum[s]=sum[s<<1]+sum[s<<1|1];
}
void PushDown(int s,int l,int r)
{
    if (mul[s]!=1)
    {
        mul[s<<1]*=mul[s];
        mul[s<<1|1]*=mul[s];
        add[s<<1]*=mul[s];
        add[s<<1|1]*=mul[s];
        sum[s<<1]*=mul[s];
        sum[s<<1|1]*=mul[s];
        mul[s]=1;
    }

    if (add[s])
    {
        add[s<<1]+=add[s];
        add[s<<1|1]+=add[s];
        int mid=(l+r)>>1;
        sum[s<<1]+=(ull)(mid-l+1)*add[s];
        sum[s<<1|1]+=(ull)(r-mid)*add[s];
        add[s]=0;
    }
}

void build(int s,int l,int r)
{
    sum[s]=add[s]=0;
    mul[s]=1;
    if (l==r) return ;
    int m=(l+r)>>1;
    build(s<<1,l,m); build(s<<1|1,m+1,r);
    PushUp(s);
}
void update(int s,int l,int r,int L,int R,ull val,int op)
{
    //printf("s=%d,l=%d,r=%d,L=%d,R=%d\n",s,l,r,L,R);
    if (L<=l&&r<=R)
    {
        if (l!=r) PushDown(s,l,r);
        if (op==1)
        {
            mul[s]*=val;
            add[s]*=val;
            sum[s]*=val;
        }
        else if (op==2)
        {
            add[s]+=val;
            sum[s]+=(ull)(r-l+1)*val;
        }
        else
        {
            mul[s]*=val;
            add[s]*=val;
            add[s]+=val;
            sum[s]=(ull)(r-l+1)*val-sum[s];
        }
        return;
    }
    PushDown(s,l,r);
    int mid=(l+r)>>1;
    if (L<=mid) update(s<<1,l,mid,L,R,val,op);
    if (R>mid) update(s<<1|1,mid+1,r,L,R,val,op);
    PushUp(s);
}
ull query(int s,int l,int r,int L,int R)
{
    if (L<=l&&r<=R) return sum[s];
    PushDown(s,l,r);
    int mid=(l+r)>>1;
    ull ans=0;
    if (L<=mid) ans+=query(s<<1,l,mid,L,R);
    if (R>mid) ans+=query(s<<1|1,mid+1,r,L,R);
    PushUp(s);
    return ans;
}
void solve(int op,int x, int y,ull val)
{
    if (op==3) val=-1;
    if (op<=3)
    {
        while (top[x]!=top[y])
        {
            if (deep[top[x]]<deep[top[y]]) swap(x, y);
            update(1,1,n,dfn[top[x]],dfn[x],val,op);
            x=fa[top[x]];
        }
        if (deep[x]>deep[y]) swap(x,y);
        update(1,1,n,dfn[x],dfn[y],val,op);
    }
    else
    {
        ull ans=0;
        while (top[x]!=top[y])
        {
            if (deep[top[x]]<deep[top[y]]) swap(x, y);
            ans+=query(1,1,n,dfn[top[x]],dfn[x]);
            x=fa[top[x]];
        }
        if (deep[x]>deep[y]) swap(x,y);
        ans+=query(1,1,n,dfn[x],dfn[y]);
        printf("%llu\n",ans);
    }
}

int main()
{
    while (scanf("%d",&n)!=EOF)
    {
        init();
        for (int i=2;i<=n;i++)
        {
            scanf("%d",&fa[i]);
            Inses(fa[i],i);
        }
        dfs1(1,0);
        dfs2(1,1);
        build(1,1,n);
        scanf("%d",&m);
        int op,u,v; ull x;
        while (m--)
        {
            scanf("%d",&op);
            if (op==1 || op==2) scanf("%d%d%llu",&u,&v,&x);
            else scanf("%d%d",&u,&v);
            solve(op,u,v,x);
        }
    }
    return 0;
}

 

原文地址:https://www.cnblogs.com/tetew/p/11293766.html

时间: 2024-10-08 10:26:05

2018焦作网络赛-E- Jiu Yuan Wants to Eat的相关文章

2018焦作网络赛 E Jiu Yuan Wants to Eat(线段树+树链剖分)

题意 对一个有1e5个点,点权初值为0的树上进行4种操作: 1.结点u到结点v上的所有点权乘x. 2.结点u到结点v上所有的点权加x. 3.结点u到结点v上所有的点权取非. 4.结点u到结点v路径上点权的和. 答案模\(2^{64}\) 思路 对操作1.2树链剖分加线段树维护即可,对操作3,取非操作为:一个二进制位上都为1 的数减去当前值,即:\(2^{64}-1-x\) , 由于答案模\(2^{64}\),通过点权用unsigned long long,只需维护\(-(x+1)\) 操作即可.

ACM-ICPC 2018 焦作赛区网络预赛 E. Jiu Yuan Wants to Eat (树链剖分-线性变换线段树)

树链剖分若不会的话可自行学习一下. 前两种操作是线性变换,模\(2^{64}\)可将线段树全部用unsigned long long 保存,另其自然溢出. 而取反操作比较不能直接处理,因为其模\(2^{64}\)的特殊性,可将其转化为线性变换. 显然 \[-x\equiv (2^{64}-1)*x (mod\ 2^{64})\] 因为\[!x = (2^{64}-1) -x \] 所以 \[ !x = (2^{64}-1) + (2^{64}-1)x\] #include<bits/stdc++

ACM-ICPC 2018 焦作赛区网络预赛 E. Jiu Yuan Wants to Eat

分析 除了树剖没想到其他解法. 用线段树维护区间和,同时针对修改区间修改操作建立两个lazy标记,一个是\(lazy_{mul}\),另一个是\(lazy_{add}\),代表区间里的数都需要先乘以\(lazy_{mul}\),再加上\(lazy_{add}\).如果一个区间需要被重复标记,那么我们可以先把新的lazy标记施加在原有的lazy上. 如果是区间乘以val,那么就可以$ lazy_{mul}=lazy_{mul} \times val,lazy_{add}=lazy_{add}\ti

ACM-ICPC 2018 焦作赛区网络预赛 E Jiu Yuan Wants to Eat (树链剖分+线段树)

题目链接:https://nanti.jisuanke.com/t/31714 题意:给你一棵树,初始全为0,有四种操作: 1.u-v乘x    2.u-v加x   3. u-v取反  4.询问u-v的和 思路: 除去第三个操作就是很简单的树链剖分+线段树多重标记下放,所以我们只要考虑怎么维护第三个操作就好了, 由题目给的取反可知:!x =  (2^64-1) - x;   但是这样维护还是很麻烦,因为这道题是对2^64取模的,我们可以 尝试把这个式子转换成只有加法和乘法的,这样就可以将其和前面

2018焦作网络赛B

dp维护一下最大值与最小值,注意边界情况的判定. #include <iostream> #include <cstring> using namespace std; const long long inf = (long long)1e18+(long long)9; long long dp[7][1005]; long long dpx[7][1005]; int f[1005]; char s[15]; int main() { int T; // int l; int

2018焦作网络赛E

区间更新加法与乘法,x取反是2^64-x-1,由于取模所以取反变成-x-1,就区间+1再*-1就可以了,最后区间询问求和. 待补 原文地址:https://www.cnblogs.com/LMissher/p/9655105.html

2018焦作网络赛 - Poor God Water 一道水题的教训

本题算是签到题,但由于赛中花费了过多的时间去滴吧格,造成了不必要的浪费以及智商掉线,所以有必要记录一下 题意:方格从1到n,每一格mjl可以选择吃鱼/巧克力/鸡腿,求走到n格时满足 1.每三格不可重复同一种食物 2.每三格均不同食物时中间格子不可吃巧克力 3.每三格前后两格不可同时吃巧克力 以上三个条件的方案数,n<1e10 太长不看版:打表+快速幂AC 长篇吐槽版 很显然的,设\(dp[n][i][j][k]\),走到第\(n\)格时第\(n-2\)格的食物是\(i\),第\(n-1\)的食物

2018焦作网络赛J

不知道题意,队友用java大数+二分过了? import java.util.Arrays; import java.util.Scanner; import java.io.*; import java.math.*; public class Main { static boolean check(BigInteger num,BigInteger n) { boolean flag = true; BigInteger a = new BigInteger("0"); BigIn

2018焦作网络赛G-Give Candies

G: Give Candies 时间限制: 1 Sec  内存限制: 128 MB 题目描述 There are N children in kindergarten. Miss Li bought them N candies.To make the process more interesting, Miss Li comes up with the rule: All the children line up according to their student number (1…N),