链接:https://www.luogu.org/problemnew/show/P1501

题面:

题目描述

一棵n个点的树,每个点的初始权值为1。对于这棵树有q个操作,每个操作为以下四种操作之一:

  • + u v c:将u到v的路径上的点的权值都加上自然数c;

  • - u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;

  • \* u v c:将u到v的路径上的点的权值都乘上自然数c;

  • / u v:询问u到v的路径上的点的权值和,求出答案对于51061的余数。

输入输出格式

输入格式:

第一行两个整数n,q

接下来n-1行每行两个正整数u,v,描述这棵树

接下来q行,每行描述一个操作

输出格式:

对于每个/对应的答案输出一行

输入输出样例

输入样例#1: 复制

3 2
1 2
2 3
* 1 3 4
/ 1 1
输出样例#1: 复制

4

说明

10%的数据保证,1<=n,q<=2000

另外15%的数据保证,1<=n,q<=5*10^4,没有-操作,并且初始树为一条链

另外35%的数据保证,1<=n,q<=5*10^4,没有-操作

100%的数据保证,1<=n,q<=10^5,0<=c<=10^4

By (伍一鸣)

思路:

写法跟线段树差不多,修改i下pushdown多维护连个标记就好了。

实现代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ls c[x][0]
#define rs c[x][1]
const int M = 4e5+;
const int inf = 1e9;
const int mod = ;
int top;
int sum[M],c[M][],val[M],fa[M],rev[M],mn[M],S[M],tmp[M];
int siz[M],mul[M],add[M];
inline void up(int x){
//cout<<sum[x]<<" "<<sum[ls]<<" "<<sum[rs]<<" "<<val[x]<<endl;
sum[x] = (sum[ls] + sum[rs] + val[x])%mod;
siz[x] = (siz[ls] + siz[rs] + )%mod;;
} inline void pushrev(int x){
swap(ls,rs); rev[x] ^= ;
} inline void pushmul(int x,int c){
mul[x] = (1LL*mul[x]*c)%mod;
add[x] = (1LL*add[x]*c)%mod;
sum[x] = (1LL*sum[x]*c)%mod;
val[x] = (1LL*val[x]*c)%mod;
//cout<<mul[x]<<" "<<val[x]<<endl;
} inline void pushadd(int x,int c){
add[x] = (add[x] + c)%mod;
val[x] = (val[x] + c)%mod;
sum[x] = (1LL*sum[x]+1LL*siz[x]*c)%mod;
} inline bool isroot(int x){
return c[fa[x]][]!=x&&c[fa[x]][]!=x;
} inline void rotate(int x){
int y = fa[x],z = fa[y];
int k = c[y][] == x;
if(!isroot(y)) c[z][c[z][]==y]=x;
fa[x] = z;
c[y][k] = c[x][k^]; fa[c[x][k^]] = y;
c[x][k^] = y; fa[y] = x;
up(y); up(x);
} inline void pushdown(int x){
if(rev[x]){
if(ls) pushrev(ls);
if(rs) pushrev(rs);
rev[x] = ;
}
if(mul[x]!=){
if(ls) pushmul(ls,mul[x]);
if(rs) pushmul(rs,mul[x]);
mul[x] = ;
}
if(add[x]){
if(ls) pushadd(ls,add[x]);
if(rs) pushadd(rs,add[x]);
add[x] = ;
}
} inline void splay(int x){
S[top=]=x;
for(int i = x;!isroot(i);i=fa[i]) S[++top] = fa[i];
while(top) pushdown(S[top--]);
while(!isroot(x)){
int y = fa[x],z = fa[y];
if(!isroot(y))
(c[y][]==x)^(c[z][]==y)?rotate(x):rotate(y);
rotate(x);
}
} inline void access(int x){
for(int y = ;x;y = x,x = fa[x])
splay(x),c[x][] = y,up(x);
} inline void makeroot(int x){
access(x); splay(x); pushrev(x);
} inline void split(int x,int y){
makeroot(x); access(y); splay(y);
} inline void link(int x,int y){
makeroot(x);fa[x] = y;
} inline void cut(int x,int y){
split(x,y); fa[x] = c[y][] = ; up(y);
} inline int findroot(int x){
access(x); splay(x);
while(ls) x = ls;
return x;
} int main()
{
int n,q,u,v,x,y,k;
scanf("%d%d",&n,&q);
for(int i = ;i <= n;i ++) val[i] = mul[i] = ;
for(int i = ;i < n;i ++){
scanf("%d%d",&u,&v);
link(u,v);
}
char op[];
while(q--){
scanf("%s",op);
scanf("%d%d",&u,&v);
if(op[] == '+') {
scanf("%d",&k);
split(u,v); pushadd(v,k);
}
else if(op[] == '-'){
scanf("%d%d",&x,&y);
cut(u,v); link(x,y);
}
else if(op[] == '*'){
scanf("%d",&k);
split(u,v); pushmul(v,k);
}
else if(op[] == '/'){
//cout<<u<<" "<<v<<endl;
split(u,v); printf("%d\n",sum[v]);
}
}
return ;
}

BZOJ 2631 tree | Luogu P1501 [国家集训队]Tree II (LCT 多重标记下放)的更多相关文章

  1. BZOJ 2631 tree / Luogu P1501 [国家集训队]Tree II (LCT,多重标记)

    题意 一棵树,有删边加边,有一条链加/乘一个数,有询问一条链的和 分析 LCT,像线段树一样维护两个标记(再加上翻转标记就是三个),维护size,就行了 CODE #include<bits/s ...

  2. LUOGU P1501 [国家集训队]Tree II (lct)

    传送门 解题思路 \(lct\),比较模板的一道题,路径加和乘的维护标记与线段树\(2\)差不多,然后剩下就没啥了.但调了我将近一下午.. 代码 #include<iostream> #i ...

  3. P1501 [国家集训队]Tree II(LCT)

    P1501 [国家集训队]Tree II 看着维护吧2333333 操作和维护区间加.乘线段树挺像的 进行修改操作时不要忘记吧每个点的点权$v[i]$也处理掉 还有就是$51061^2=2607225 ...

  4. 洛谷 P1501 [国家集训队]Tree II 解题报告

    P1501 [国家集训队]Tree II 题目描述 一棵\(n\)个点的树,每个点的初始权值为\(1\).对于这棵树有\(q\)个操作,每个操作为以下四种操作之一: + u v c:将\(u\)到\( ...

  5. P1501 [国家集训队]Tree II LCT

    链接 luogu 思路 简单题 代码 #include <bits/stdc++.h> #define ls c[x][0] #define rs c[x][1] using namesp ...

  6. 洛谷P1501 [国家集训队]Tree II(LCT,Splay)

    洛谷题目传送门 关于LCT的其它问题可以参考一下我的LCT总结 一道LCT很好的练习放懒标记技巧的题目. 一开始看到又做加法又做乘法的时候我是有点mengbi的. 然后我想起了模板线段树2...... ...

  7. 【刷题】洛谷 P1501 [国家集训队]Tree II

    题目描述 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 u2 v2:将树中原有的 ...

  8. 洛谷P1501 [国家集训队]Tree II(LCT)

    题目描述 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 u2 v2:将树中原有的 ...

  9. p1501 [国家集训队]Tree II

    传送门 分析 lct板子题 单独维护一下加和乘的情况即可 维护方法和维护翻转差不多 代码 #include<iostream> #include<cstdio> #includ ...

随机推荐

  1. SpringMVC拦截静态资源的解决方法

    本文中的各软件版本简要信息: IDE:Myeclise17 JDK:1.8.0_111 spring:5.1.8 springMVC:5.1.8 mybatis:3.2.2 Tomcat:9.0 在使 ...

  2. docker学习---docker基础知识

    目录 docker的基础 1.安装docker 2.使用镜像 3.镜像迁移|导入和导出 4.docker Hub介绍 5.搭建私有镜像仓库 5.1.docker开源的镜像分发工具--docker Re ...

  3. B/S上传大文件的解决方案

    第一点:Java代码实现文件上传 FormFile file = manform.getFile(); String newfileName = null; String newpathname =  ...

  4. 小米oj 重拍数组求最大和

     重排数组求最大和 序号:#34难度:困难时间限制:1000ms内存限制:10M 描述 假设有一个n元素的数组(数组的元素索引从1开始),针对这个数组有q个查询请求,每个请求由一对整数li,ri组成, ...

  5. 【csp模拟赛2】 爆搜 方格加数

    [题目描述] xyz1048576正在玩一个关于矩阵的游戏. 一个n*m的矩阵,矩阵中每个数都是[1,12]内的整数.你可以执行下列两个操作任意多次: (1)指定一行,将该行所有数字+1. (2)指定 ...

  6. 逻辑回归原理 面试 Logistic Regression

    逻辑回归是假设数据服从独立且服从伯努利分布,多用于二分类场景,应用极大似然估计构造损失函数,并使用梯度下降法对参数进行估计.

  7. 【java设计模式】-03抽象工厂模式

    抽象工厂 简述 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类.在抽象工厂模式中,接口是负责创建一个相关对象的工厂 ...

  8. linux环境中关闭tomcat,通过shutdown.sh无法彻底关闭--线程池

    最近测试环境上测试的项目通过shutdown.sh始终无法彻底关闭. 之前临时解决方法两种: 第一:通过ps -ef|grep tomcat查看到tomcat的进程直接使用kill来杀死进程. 第二: ...

  9. Bootstrap4从入门到精通视频教程

    一.布局 0.课件1.Bootstrap介绍_栅格系统2.禁用响应式_响应式分界点 二.内容 3.排版_代码4.图片_图片框5.表格 三.公共样式 6.边框_浮动7.颜色_Display显示属性8.文 ...

  10. Django中三种方式写form表单

    除了在html中自己手写form表单外,django还可以通过 继承django.forms.Form 或django.forms.ModelForm两个类来自动生成form表单,下面依次利用三种方式 ...