一、题目链接

二、题意

给定一棵树,有四种操作:

$1\ u\ v\ x$:把节点$u$到$v$路径上的所有点的权值乘以$x$;

$2\ u\ v\ x$:把节点$u$到$v$路径上的所有点的权值加上$x$;

$3\ u\ v$:把节点$u$到$v$路径上的所有点的权值取反(~操作);

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

所有操作都需要$mod\ 2^{64}$。

三、思路

操作1、2和4是很裸的树链剖分。关键是操作3。这里有个小技巧:对任意一个数字$x$取反,都等于$-(x+1)$。对于此题的$unsigned\ long\ long$类型,同样适用($-1$就是$1111\cdots1111_{(2)}=2^{64}-1$)。明白这个以后,取反操作可以变成加法和乘法。

然后要注意的是,线段树的区间加和区间乘的顺序问题,这里也有个技巧:如果区间$[l,r]$之前的和是$sum$,这个区间先加了一个$x$,再乘了一个$y$,那么可以变成$sum*y+x*y$。即让这个区间先乘一个$y$,再加上$x*y$。这样就可以保证以先乘后加的顺序不出问题了。

然后这题就愉快地AC了。

结论:对任意一个数$x$取反,无论这个数的类型是什么($int,unsigned\ int,long\ long,unsigned\ long\ long$都可以),都等于$-(x+1)$。

四、代码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
typedef unsigned long long ULL;
struct edge {
    int to, next;
    edge(, ): to(to), next(next) {}
} es[MAXN * ];
int head[MAXN], ecnt;
int f[MAXN], deep[MAXN], siz[MAXN], zson[MAXN], top[MAXN], o2n[MAXN], dfscnt;
int n, q;
ULL a[MAXN];

namespace st {
    struct node {
        ULL sum, slazy, plazy;
        node(ULL a1 = , ULL a2 = , ULL a3 = ): sum(a1), slazy(a2), plazy(a3) {}
    } ns[MAXN * ];
    void init() {
        , t =  * n + ; i < t; ++i)ns[i] = node(, , );
    }
    void pushdown(int rt, int l, int r) {
        , rch = rt <<  | , mid = (l + r) >> ;
         || ns[rt].plazy != ) {
            ns[lch].sum = ns[lch].sum * ns[rt].plazy + (mid - l + ) * ns[rt].slazy;
            ns[rch].sum = ns[rch].sum * ns[rt].plazy + (r - mid) * ns[rt].slazy;
            ns[lch].plazy *= ns[rt].plazy;
            ns[rch].plazy *= ns[rt].plazy;
            ns[lch].slazy = ns[lch].slazy * ns[rt].plazy + ns[rt].slazy;
            ns[rch].slazy = ns[rch].slazy * ns[rt].plazy + ns[rt].slazy;
            ns[rt].plazy = , ns[rt].slazy = ;
        }
    }
    , , int r = n) {
        if(l > ur || r < ul)return;
        if(l >= ul && r <= ur) {
            )ns[rt].sum += x * ULL(r - l + ), ns[rt].slazy += x;
            else ns[rt].sum *= x, ns[rt].plazy *= x, ns[rt].slazy *= x;
            return;
        }
        pushdown(rt, l, r);
        ;
        , l, mid);
         | , mid + , r);
        ns[rt].sum = ns[rt << ].sum + ns[rt <<  | ].sum;
    }
    ULL query(, , int r = n) {
        if(l > qr || r < ql)return 0LL;
        if(l >= ql && r <= qr)return ns[rt].sum;
        pushdown(rt, l, r);
        ;
        ULL res = ;
        , l, mid);
         | , mid + , r);
        return res;
    }
};
void add(int from, int to) {
    es[++ecnt] = edge(to, head[from]), head[from] = ecnt;
}
void init() {
    memset(head, , ]) * (n + ));
    ecnt = ;
    memset(zson, , ]) * (n + ));
    dfscnt = ;
    st::init();
}
void dfs1(int root, int par) {
    deep[root] = deep[par] + , f[root] = par, siz[root] = ;
    ;
    for(int i = head[root]; i; i = es[i].next) {
        int to = es[i].to;
        if(to != par) {
            dfs1(to, root);
            siz[root] += siz[to];
            if(ms < siz[to]) {
                ms = siz[to], zson[root] = to;
            }
        }
    }
}
void dfs2(int root, int par, int tp) {
    top[root] = tp, o2n[root] = ++dfscnt;
    st::update(dfscnt, dfscnt, a[root], );
    if(!zson[root])return;
    dfs2(zson[root], root, tp);
    for(int i = head[root]; i; i = es[i].next) {
        int to = es[i].to;
        if(to != par && to != zson[root]) {
            dfs2(to, root, to);
        }
    }
}
void update(int u, int v, ULL x, int type) {
    int tu = top[u], tv = top[v];
    while(tu != tv) {
        if(deep[tu] >= deep[tv]) {
            st::update(o2n[tu], o2n[u], x, type);
            u = f[tu], tu = top[u];
        }
        else {
            st::update(o2n[tv], o2n[v], x, type);
            v = f[tv], tv = top[v];
        }
    }
    if(o2n[u] <= o2n[v])st::update(o2n[u], o2n[v], x, type);
    else st::update(o2n[v], o2n[u], x, type);
}
ULL query(int u, int v) {
    int tu = top[u], tv = top[v];
    ULL res = ;
    while(tu != tv) {
        if(deep[tu] >= deep[tv]) {
            res += st::query(o2n[tu], o2n[u]);
            u = f[tu], tu = top[u];
        }
        else {
            res += st::query(o2n[tv], o2n[v]);
            v = f[tv], tv = top[v];
        }
    }
    if(o2n[u] <= o2n[v])res += st::query(o2n[u], o2n[v]);
    else res += st::query(o2n[v], o2n[u]);
    return res;
}
int main() {
//    freopen("e.in","r",stdin);
    int fa, op, u, v;
    ULL x;
    while(~scanf("%d", &n)) {
        init();
        ; i <= n; ++i) {
            scanf("%d", &fa);
            add(fa, i), add(i, fa);
        }
        dfs1(, );
        dfs2(, , );
        scanf("%d", &q);
        while(q--) {
            scanf("%d", &op);
            ) {
                scanf("%d%d%llu", &u, &v, &x);
                update(u, v, x, );
            }
            ) {
                scanf("%d%d%llu", &u, &v, &x);
                update(u, v, x, );
            }
            ) {
                scanf("%d%d", &u, &v);
                update(u, v, , );
                update(u, v, -, );
            }
            else {
                scanf("%d%d", &u, &v);
                ULL res = query(u, v);
                printf("%llu\n", res);
            }
        }
    }
    ;
}

2018ICPC网络赛(焦作站)E题题解的更多相关文章

  1. 2018ICPC网络赛(焦作站)K题题解

    一.题目链接 https://nanti.jisuanke.com/t/31720 二.题意 给$N$种船只,第$i$种船的载重量是$V_i$,数量是$2^{C_i}-1$.接下来有$Q$次询问,每次 ...

  2. 2018ICPC网络赛(徐州站)A题题解

    一.题目链接 https://nanti.jisuanke.com/t/31453 二.题意 给定$N$个位置,$2^k$种颜色,让你去涂色,条件是相邻的两种颜色类型异或值的二进制表示不全为$1$(以 ...

  3. 2013 ACM-ICPC亚洲区域赛南京站C题 题解 轮廓线DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4804 题目大意 给你一个 \(n \times m\) 的矩形区域.你需要用 \(1 \times 1 ...

  4. 2019CCPC网络预选赛 八道签到题题解

    目录 2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛 6702 & 6703 array 6704 K-th occurrence 6705 path 6706 huntian o ...

  5. HDU 4730 We Love MOE Girls (2013成都网络赛,签到水题)

    We Love MOE Girls Time Limit: 1000/500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  6. SCNU省选校赛第二场B题题解

    今晚的校赛又告一段落啦,终于"开斋"了! AC了两题,还算是满意的,英语还是硬伤. 来看题目吧! B. Array time limit per test 2 seconds me ...

  7. Building Fire Stations 39届亚洲赛牡丹江站B题

    题意:      给你一棵树,让你再里面选取两个点作为**点,然后所有点的权值是到这两个点中最近的那个的距离,最后问距离中最长的最短是多少,输出距离还有那两个点(spj特判). 思路:      现场 ...

  8. hdu 5038 (2014北京网络赛G 排序水题)

    题意:有n个数字,带入10000 - (100 - ai) ^ 2公式得到n个数,输出n个数中频率最大的数,如果有并列就按值从小到大都输出输出,如果频率相同的数字是全部的n个数,就输出Bad....题 ...

  9. 2018ACM-ICPC亚洲区域赛南京站I题Magic Potion(网络流)

    http://codeforces.com/gym/101981/attachments 题意:有n个英雄,m个敌人,k瓶药剂,给出每个英雄可以消灭的敌人的编号.每个英雄只能消灭一个敌人,但每个英雄只 ...

随机推荐

  1. header 输出原始的php报头文件

    header() 函数向客户端发送原始的 HTTP 报头. 认识到一点很重要,即必须在任何实际的输出被发送之前调用 header() 函数 (在 PHP 4 以及更高的版本中,您可以使用输出缓存来解决 ...

  2. Redis学习第二课:Redis String类型及操作

    Strings类型 String是最简单的类型,一个Key对应一个Value,String类型是二进制安全的,可以包含任何数据,比如jpg图片或序列化的对象. Strings类型的操作: Set:设置 ...

  3. OC基础:block.字面量 分类: ios学习 OC 2015-06-22 19:08 155人阅读 评论(0) 收藏

    block 块语法,可以用block去保存一段代码,或者封装一段代码. block 实际是由c语言实现的,执行效率很高. block 实际借鉴了函数指针的语法. block,在多线程.异步任务,集合遍 ...

  4. linux下sprintf_s函数的替代

    error code: ]; sprintf_s(buf, , "predicted position:(%3d, %3d)", predict_pt.x, predict_pt. ...

  5. Tensorflow中的滑动平均模型

    原文链接 在Tensorflow的教程里面,使用梯度下降算法训练神经网络时,都会提到一个使模型更加健壮的策略,即滑动平均模型. 基本思想 在使用梯度下降算法训练模型时,每次更新权重时,为每个权重维护一 ...

  6. [LeetCode&Python] Problem 766. Toeplitz Matrix

    A matrix is Toeplitz if every diagonal from top-left to bottom-right has the same element. Now given ...

  7. POJ 2312:Battle City(BFS)

    Battle City Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9885   Accepted: 3285 Descr ...

  8. 51Nod:1003 阶乘后面0的数量

    1003 阶乘后面0的数量  基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题  收藏  关注 n的阶乘后面有多少个0? 6的阶乘 = 1*2*3*4*5*6 = 72 ...

  9. 第二百七十六节,MySQL数据库,【显示、创建、选定、删除数据库】,【用户管理、对用户增删改查以及授权】

    MySQL数据库,[显示.创建.选定.删除数据库],[用户管理.对用户增删改查以及授权] 1.显示数据库 SHOW DATABASES;显示数据库 SHOW DATABASES; mysql - 用户 ...

  10. elasticsearch问题解决之分片副本UNASSIGNED

    在上一篇文章中,我记录了在windows下同一台机器上搭建es集群的步骤,第二天在向集群中创建索引的时候,出现了分片副本未分配的情况(UNASSIGNED). 虽然并不影响数据的插入和查询,但是有问题 ...