传送门


题目的操作大概是:求某个点到根的链的逆序对,然后对这条链做区间赋值

求某个点到根的链,就是LCT中的access操作,所以我们每一次把access过后的链打上标记,就可以做到区间赋值了。

计算答案只需要在access的过程中用树状数组求一下逆序对即可。

#include<bits/stdc++.h>
#define PII pair < int , int >
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c) && c != EOF){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    if(c == EOF)
        exit(0);
    while(isdigit(c)){
        a = a * 10 + c - 48;
        c = getchar();
    }
    return f ? -a : a;
}

const int MAXN = 1e5 + 7;
struct node{
    int fa , ch[2] , sz;
    bool mark;
}Tree[MAXN];
int N , cnt , val[MAXN] , lsh[MAXN];
long long ans;
queue < PII > q;

namespace BIT{
    #define lowbit(x) ((x) & -(x))
    int BIT[MAXN];

    inline void add(int x , int num){
        while(x <= cnt){
            BIT[x] += num;
            x += lowbit(x);
        }
    }

    inline int get(int x){
        int sum = 0;
        while(x){
            sum += BIT[x];
            x -= lowbit(x);
        }
        return sum;
    }
}
using namespace BIT;

inline bool nroot(int x){
    return Tree[Tree[x].fa].ch[0] == x || Tree[Tree[x].fa].ch[1] == x;
}

inline bool son(int x){
    return Tree[Tree[x].fa].ch[1] == x;
}

inline void pushup(int x){
    Tree[x].sz = Tree[Tree[x].ch[0]].sz + Tree[Tree[x].ch[1]].sz + 1;
}

inline void rotate(int x){
    bool f = son(x);
    int y = Tree[x].fa , z = Tree[y].fa , w = Tree[x].ch[f ^ 1];
    Tree[x].fa = z;
    if(nroot(y))
        Tree[z].ch[son(y)] = x;
    Tree[y].fa = x;
    Tree[x].ch[f ^ 1] = y;
    Tree[y].ch[f] = w;
    if(w)
        Tree[w].fa = y;
    pushup(y);
}

inline void mark(int x){
    Tree[x].mark ^= 1;
    swap(Tree[x].ch[0] , Tree[x].ch[1]);
}

inline void pushdown(int x){
    if(Tree[x].mark){
        mark(Tree[x].ch[0]);
        mark(Tree[x].ch[1]);
        Tree[x].mark = 0;
    }
}

void pushdown_all(int x){
    if(nroot(x))
        pushdown_all(Tree[x].fa);
    pushdown(x);
}

inline void Splay(int x){
    pushdown_all(x);
    while(nroot(x)){
        if(nroot(Tree[x].fa))
            rotate(son(x) == son(Tree[x].fa) ? Tree[x].fa : x);
        rotate(x);
    }
    pushup(x);
}

inline void access(int x){
    int y = x;
    x = Tree[x].fa;
    for( ; x ; y = x , x = Tree[x].fa){
        Splay(x);
        int t = x;
        while(Tree[t].ch[1])
            pushdown(t = Tree[t].ch[1]);
        q.push(PII(val[t] , Tree[Tree[x].ch[0]].sz + 1));
        ans += 1ll * get(val[t] - 1) * (Tree[Tree[x].ch[0]].sz + 1);
        add(val[t] , Tree[Tree[x].ch[0]].sz + 1);
        Tree[x].ch[1] = y;
        pushup(x);
    }
}

inline void clear(){
    while(!q.empty()){
        PII t = q.front();
        q.pop();
        add(t.first , -t.second);
    }
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    freopen("out","w",stdout);
#endif
    N = read();
    for(int i = 1 ; i <= N ; ++i)
        val[i] = lsh[i] = read();
    sort(lsh + 1 , lsh + N + 1);
    cnt = unique(lsh + 1 , lsh + N + 1) - lsh - 1;
    for(int i = 1 ; i <= N ; ++i)
        val[i] = lower_bound(lsh + 1 , lsh + cnt + 1 , val[i]) - lsh;
    for(int i = 1 ; i < N ; ++i){
        int a = read() , b = read();
        ans = 0;
        Tree[b].fa = a;
        access(b);
        Splay(b);
        cout << ans << '\n';
        clear();
    }
    return 0;
}

LOJ2831 JOISC2018 道路建设 LCT、树状数组的更多相关文章

  1. [JOISC2018]道路建设 LCT

    [JOISC2018]道路建设 LOJ传送门 考的时候打的大暴力,其实想到了LCT,但是思路有点没转过来.就算想到了估计也不能切,我没有在考场写LCT的自信... 其实这题不是让你直接用LCT维护答案 ...

  2. bzoj 3779 重组病毒 —— LCT+树状数组(区间修改+区间查询)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 RELEASE操作可以对应LCT的 access,RECENTER则是 makeroo ...

  3. [Codeforces1137F]Matches Are Not a Child's Play——LCT+树状数组

    题目链接: [Codeforces1137F]Matches Are Not a Child's Play 题目大意: 我们定义一棵树的删除序列为:每一次将树中编号最小的叶子删掉,将该节点编号加入到当 ...

  4. hdu 6200 mustedge mustedge(并查集+树状数组 或者 LCT 缩点)

    hdu 6200 mustedge mustedge(并查集+树状数组 或者 LCT 缩点) 题意: 给一张无向连通图,有两种操作 1 u v 加一条边(u,v) 2 u v 计算u到v路径上桥的个数 ...

  5. 【BZOJ2870】最长道路tree 点分治+树状数组

    [BZOJ2870]最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来 ...

  6. 【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询

    题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作 ...

  7. BZOJ 1103: [POI2007]大都市meg [DFS序 树状数组]

    1103: [POI2007]大都市meg Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2221  Solved: 1179[Submit][Sta ...

  8. 【BZOJ-1103】大都市meg 树状数组 + DFS序

    1103: [POI2007]大都市meg Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2009  Solved: 1056[Submit][Sta ...

  9. 【BZOJ-3648】寝室管理 环套树 + 树状数组 + 点分治

    3648: 寝室管理 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 239  Solved: 106[Submit][Status][Discuss] ...

随机推荐

  1. Shell从入门到精通进阶之三:表达式与运算符

    3.1 条件表达式 表达式 示例 [ expression ] [ 1 -eq 1 ]  ` expression ` ` 1 -eq 1 ` test expression test 1 -eq 1 ...

  2. MySQL备份与恢复之percona-xtrabackup实现增量备份及恢复 实例

    innobackupex 的使用方法1.完全备份 参数一是完全备份地址 完全备份到/data/mysql/back_up/all_testdb_20140612 目录下innobackupex --u ...

  3. [五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的

      Launcher启动类 本文是双亲委派机制的源码分析部分,类加载机制中的双亲委派模型对于jvm的稳定运行是非常重要的 不过源码其实比较简单,接下来简单介绍一下   我们先从启动类说起 有一个Lau ...

  4. AppBoxFuture(六): 前端组件化开发

      前面几篇都是在介绍结构化与非结构化的数据存储,本篇换换口味介绍一下框架是如何实现前端组件化开发的.首先得感谢Vue.ElementUI等优秀的前端开源项目,这些项目帮助作者快速实现了框架的两个前端 ...

  5. 痞子衡嵌入式:飞思卡尔i.MX RT系列MCU启动那些事(3)- Serial Downloader模式(sdphost/MfgTool)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RT系列MCU的Serial Downloader模式. 在上一篇文章 Boot配置(BOOT Pin, eFUSE) ...

  6. CentOS 7 镜像文件各个版本区别

    CentOS ISO 镜像文件的功能 引导安装 CentOS ISO 镜像文件包含有安装程序,官方称其为 Anaconda,用来引导安装 CentOS 提供 CentOS 的安装文件 镜像文件不一定包 ...

  7. 树莓派3B+通过路由器进SSH和VNC

    1.打开树莓派官网 www.raspberrypi.org 选择 ”Raspbian Stretch with desktop and recommended software“ 并下载 镜像包含推荐 ...

  8. QT 自定义模态对话框

    新建一个MsgBox类 msgbox.h 代码 #ifndef MSGBOX_H #define MSGBOX_H #include <QDialog> #include <QPus ...

  9. AV-TEST杀毒软件能力测试(2018年1月-12月)杀毒软件排名

    2018年1月到12月,AV-TEST攻击了实验室中无数的Windows系统,在830多项单独测试中测试了7种杀毒软件和5种快捷工具. 1.测试概述 在长期测试中,实验室在各种实际场景中测试了杀毒软件 ...

  10. C++析构函数可虚性探究

    C++虚析构函数 析构函数是用来释放对象所申请的资源的函数. 当类内没有自定义的析构函数时,系统会自动调用默认的析构函数. 那么析构函数能否为虚函数呢? 虚函数的意义在于实现“多态性”.即:不同的个体 ...