传送门

题意:写一个数据结构,支持森林上:连边、删边、翻转点的颜色(黑白)、查询以某一点为根的某棵树上所有黑色点到根的距离和。$\text{点数} \leq 10^5 , \text{操作数} \leq 3 \times 10^5$


连边删边不用说就是$LCT$,而边有边权,显然需要化边为点进行操作

考虑如何维护最后一个信息。考虑$LCT$中$Splay$上的某一棵子树,$Splay$的根为$x$,其左子树为$lson$,右子树为$rson$,虚子树统一称为$son$

如果我们已经计算好了$lson,rson,son$的答案,如何计算$x$的答案?

因为$Splay$上对应原树的一条链,所以:

①$rson$与$son$中的黑点在需要经过左子树中的所有边和$x$(如果$x$代表一条边),所以答案需要加上$rson$与$son$中的黑点总数$\times\,$($x$代表的边的边权$+lson$中的实链边权总和)

②如果$x$代表一个黑点,它需要经过左子树中的所有边,所以答案需要加上$lson$中的实链边权总和

③答案再加上$lson,rson,son$的答案即可。

所以我们需要维护子树的边权总和、黑点总数,才能够计算答案。

需要注意以下几点:

①边权总和不需要将虚子树的计算在内(显然虚子树内的点都在虚子树上传的时候计算完了答案,所以在其他点上不会产生贡献),只需要把实链的计算上去

②因为需要$makeroot$操作,所以你还要记录将左右子树反过来之后的答案,这样才能正确下传标记

③注意一点:翻转左右子树对虚子树内部答案没有影响,所以虚子树答案直接上传不经过翻转的即可

 #include<bits/stdc++.h>
 #define lch Tree[x].ch[0]
 #define rch Tree[x].ch[1]
 #define int long long
 //This code is written by Itst
 using namespace std;

 inline int read(){
     ;
     ;
     char c = getchar();
     while(c != EOF && !isdigit(c)){
         if(c == '-')
             f = ;
         c = getchar();
     }
     while(c != EOF && isdigit(c)){
         a = (a << ) + (a << ) + (c ^ ');
         c = getchar();
     }
     return f ? -a : a;
 }

 ;
 struct node{
     ] , size , non_size;
     long long val , sumE , sumL , non_sum , sumR;
     bool mark , col;
 }Tree[MAXN << ];
 int N , M , K , cntNode;

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

 inline bool son(int x){
     ] == x;
 }

 inline void pushup(int x){
     Tree[x].size = Tree[lch].size + Tree[rch].size + Tree[x].non_size + Tree[x].col;
     Tree[x].sumE = Tree[lch].sumE + Tree[rch].sumE + Tree[x].val;
     Tree[x].sumL = Tree[lch].sumL + Tree[rch].sumL + Tree[x].non_sum +(Tree[rch].size + Tree[x].non_size + Tree[x].col) * (Tree[x].val + Tree[lch].sumE);
     Tree[x].sumR = Tree[lch].sumR + Tree[rch].sumR + Tree[x].non_sum + (Tree[lch].size + Tree[x].non_size + Tree[x].col) * (Tree[x].val + Tree[rch].sumE);
 }

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

 inline void reverse(int x){
     Tree[x].mark ^= ;
     swap(lch , rch);
     swap(Tree[x].sumL , Tree[x].sumR);
 }

 inline void pushdown(int x){
     if(Tree[x].mark){
         reverse(lch);
         reverse(rch);
         Tree[x].mark = ;
     }
 }

 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(Tree[x].fa) == son(x) ? Tree[x].fa : x);
         rotate(x);
     }
     pushup(x);
 }

 inline void access(int x){
      ; x ; y = x , x = Tree[x].fa){
         Splay(x);
         Tree[x].non_size = Tree[x].non_size + Tree[Tree[x].ch[]].size - Tree[y].size;
         Tree[x].non_sum = Tree[x].non_sum + Tree[Tree[x].ch[]].sumL - Tree[y].sumL;
         Tree[x].ch[] = y;
         pushup(x);
     }
 }

 inline void makeroot(int x){
     access(x);
     Splay(x);
     reverse(x);
 }

 inline void split(int x , int y){
     makeroot(x);
     access(y);
     Splay(y);
 }

 inline void _link(int x , int y){
     makeroot(x);
     makeroot(y);
     Tree[y].non_size += Tree[x].size;
     Tree[y].non_sum += Tree[x].sumL;
     Tree[x].fa = y;
     pushup(y);
 }

 inline void link(int x , int y , int val){
     Tree[++cntNode].val = val;
     _link(x , cntNode);
     _link(y , cntNode);
 }

 inline void cut(int x , int y){
     split(y , x);
     if(Tree[y].fa == x){
         Tree[y].ch[] = ;
         pushup(y);
     }
     else
         Tree[y].fa = Tree[Tree[y].fa].ch[] = ;
     lch = Tree[lch].fa = ;
     pushup(x);
 }

 inline void query(int x){
     makeroot(x);
     printf("%lld\n" , Tree[x].sumL);
 }

 inline char getc(){
     char c = getchar();
     while(!isupper(c))
         c = getchar();
     return c;
 }

 signed main(){
 #ifndef ONLINE_JUDGE
     freopen("558.in" , "r" , stdin);
     freopen("558.out" , "w" , stdout);
 #endif
     N = read();
     M = read();
     K = read();
     cntNode = N;
     int a , b , w;
     while(M--){
         a = read();
         b = read();
         w = read();
         link(a , b , w);
     }
     while(K--)
         switch(getc()){
         case 'L':
             a = read();
             b = read();
             w = read();
             link(a , b , w);
             break;
         case 'C':
             a = read();
             b = read();
             cut(a , b);
             break;
         case 'F':
             a = read();
             makeroot(a);
             Tree[a].col ^= ;
             pushup(a);
             break;
         case 'Q':
             query(read());
             break;
         }
     ;
 }

LOJ558 我们的 CPU 遭到攻击 LCT的更多相关文章

  1. loj558 「Antileaf's Round」我们的CPU遭到攻击

    考完了可以发题解了. 做法是link-cut tree维护子树信息,并不需要维护黑树白树那些的. 下面是一条重链: 如果4是根的话,那么在splay上是这样的: 在splay中,子树的信息都已经计算完 ...

  2. LCT总结——应用篇(附题单)(LCT)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--概念篇戳这里 题单 灰常感谢XZY巨佬提供的强力资磁!(可参考XZY巨佬的博客总结) 题单对于系 ...

  3. 【转载】LCT题单

    本篇博客的题单转载自FlashHu大佬的博客:LCT总结--应用篇(附题单)(LCT). 关于\(LCT\)可以查看这篇博客:\(LCT\)入门. 这里面有些题解的链接是空链接,尚未补全. 维护链信息 ...

  4. LCT 入门

    这是一份 \(\rm LCT\) 入门总结. 关于 \(\rm LCT\) 的复杂度这里不会提及,只会记录 \(\rm LCT\) 的基本操作和经典例题,但神奇的 \(\rm LCT\) 虽然常数巨大 ...

  5. 【H3C交换机】cpu各个进程的详细说明

    display cpu-usage命令用来查看设备CPU占用率的统计信息,以及各个进程的cpu占用率. 各个进程详细说明如下,不同软件版本.盒式和框式的cpu进程略有不同,详细信息可以查看手册中的命令 ...

  6. 关于 Spring Security 5 默认使用 Password Hash 算法

    账户密码存储的安全性是一个很老的话题,但还是会频频发生,一般的做法是 SHA256(userInputpwd+globalsalt+usersalt) 并设置密码时时要求长度与大小写组合,一般这样设计 ...

  7. A Survey on the Security of Stateful SDN Data Planes

    论文摘要: 本文为读者提供新兴的SDN带状态数据平面,集中关注SDN数据平面编程性带来的隐患. I部分 介绍 A.带状态SDN数据平面的兴起 B.带状态数据平面带来的安全隐患 引出带状态数据平面的安全 ...

  8. Bitcoin: A Peer-to-Peer Electronic Cash System(比特币论文翻译)

    比特币历史: 2008年,比特币论文诞生 2009年1月,第一批比特币诞生 2011年4月,比特币价格第一次达到了1美元 2011年6月,涨到30美元,然后开始跌 2013年1月,4美元 2013年1 ...

  9. CVE-2019-0708 漏洞分析及相关测试

    在CVE-2019-0708公布后几天就已经尝试过复现该漏洞,但借助当时exp并没能成功复现反弹shell的过程遂放弃,故借助这次漏洞复现报告再来尝试复现该漏洞,因为还在大三学习中,有很多知识还没有掌 ...

随机推荐

  1. TurboLinux系统管理习题一

    TurboLinux系统管理习题一 1. 使用vi编辑文本只读时,强制存盘并退出的命令是?(单选题)A :w!        B :q!       C   :wq!        D   :e!答案 ...

  2. php+smarty轻松开发微社区/微论坛

    今天我们就来分析微社区的基本功能构成吧.首先,每个论坛最主要的是会员在对应的版块下发帖,或者在感兴趣的主题帖下跟帖盖楼.其次,会员能时时看到帖子或版块的基本信息.所以主要大块是: 前台:会员的注册登录 ...

  3. Android--很实用的图片工具类

    import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; imp ...

  4. jpa 联表查询 返回自定义对象 hql语法 原生sql 语法 1.11.9版本

    -----业务场景中经常涉及到联查,jpa的hql语法提供了内连接的查询方式(不支持复杂hql,比如left join ,right join).  上代码了 1.我们要联查房屋和房屋用户中间表,通过 ...

  5. BigDecimal遇到的问题,大伙也说说

    一:相除精度丢失的问题 BigDecimal的api除法相对加减乘要实现的复杂多了,只介绍常用的我遇到的问题: 问题:两数相除,如果9/3=3整除没问题,但是10/3=0.33333333...... ...

  6. Nginx Linux安装与部署

    Nginx (engine x) 是一个高性能的HTTP和反向代理服务,也是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行. ...

  7. python socket 套接字编程 单进程服务器 实现多客户端访问

    服务器: import socket #单进程服务器 实现多客户端访问 IO复用 #吧所有的客户端套接字 放在一个列表里面,一次又一次的便利过滤 server = socket.socket(sock ...

  8. NetBeans数据库笔记---三层架构

    1.创建数据库,数据表 用MySQL数据库和Navicat for MySQL工具创建表 2.创建实体类——反应表结构(列——变量) 也就是对应表建立的gets和sets方法,实体类的名字一般都与数据 ...

  9. 【PAT】B1072 开学寄语(20 分)

    代码注释应该很清晰 先存下违禁品,放到数组中,未使用map #include<cstdio> #include<string.h> int wupin[10],N,M; boo ...

  10. MySQL基本简单操作03

    MySQL基本简单操作 现在我创建了一个数据表,表的内容如下: mysql> select * from gubeiqing_table; +----------+-----+ | name | ...