BZOJ 2631 tree | Luogu P1501 [国家集训队]Tree II (LCT 多重标记下放)
链接: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行,每行描述一个操作
输出格式:
对于每个/对应的答案输出一行
输入输出样例
说明
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 多重标记下放)的更多相关文章
- BZOJ 2631 tree / Luogu P1501 [国家集训队]Tree II (LCT,多重标记)
题意 一棵树,有删边加边,有一条链加/乘一个数,有询问一条链的和 分析 LCT,像线段树一样维护两个标记(再加上翻转标记就是三个),维护size,就行了 CODE #include<bits/s ...
- LUOGU P1501 [国家集训队]Tree II (lct)
传送门 解题思路 \(lct\),比较模板的一道题,路径加和乘的维护标记与线段树\(2\)差不多,然后剩下就没啥了.但调了我将近一下午.. 代码 #include<iostream> #i ...
- P1501 [国家集训队]Tree II(LCT)
P1501 [国家集训队]Tree II 看着维护吧2333333 操作和维护区间加.乘线段树挺像的 进行修改操作时不要忘记吧每个点的点权$v[i]$也处理掉 还有就是$51061^2=2607225 ...
- 洛谷 P1501 [国家集训队]Tree II 解题报告
P1501 [国家集训队]Tree II 题目描述 一棵\(n\)个点的树,每个点的初始权值为\(1\).对于这棵树有\(q\)个操作,每个操作为以下四种操作之一: + u v c:将\(u\)到\( ...
- P1501 [国家集训队]Tree II LCT
链接 luogu 思路 简单题 代码 #include <bits/stdc++.h> #define ls c[x][0] #define rs c[x][1] using namesp ...
- 洛谷P1501 [国家集训队]Tree II(LCT,Splay)
洛谷题目传送门 关于LCT的其它问题可以参考一下我的LCT总结 一道LCT很好的练习放懒标记技巧的题目. 一开始看到又做加法又做乘法的时候我是有点mengbi的. 然后我想起了模板线段树2...... ...
- 【刷题】洛谷 P1501 [国家集训队]Tree II
题目描述 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 u2 v2:将树中原有的 ...
- 洛谷P1501 [国家集训队]Tree II(LCT)
题目描述 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 u2 v2:将树中原有的 ...
- p1501 [国家集训队]Tree II
传送门 分析 lct板子题 单独维护一下加和乘的情况即可 维护方法和维护翻转差不多 代码 #include<iostream> #include<cstdio> #includ ...
随机推荐
- JavaScript程序设计——FOR循环
FOR循环流程图: 1.编写求6!的阶乘的代码 2.编写10个10相加的和 3.编写1+2+3+...+10连续相加的和 4.编写1+(1+2)+(1+2+3)+...+(1+2+3+...+10)连 ...
- Luogu P1198 [JSOI2008]最大数 单调队列/ST表
开一个单调队列,下标递增,值递减. 然后在上面二分最大数. 如果加上并查集可以做到接近线性. 还有一种是插入一个数然后,从后向前更新ST表. #include<cstdio> #inclu ...
- springboot注释层分解图
- asp.net上传大文件的解决方案
IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag 客户端每次提交下载请求时,服务 ...
- 51nod1040 最大公约数之和,欧拉函数或积性函数
1040 最大公约数之和 给出一个n,求1-n这n个数,同n的最大公约数的和.比如:n = 6时,1,2,3,4,5,6 同6的最大公约数分别为1,2,3,2,1,6,加在一起 = 15 看起来很简单 ...
- Java中基本数据类型
在数据类型中,最常用也是最基础的数据类型,被称作基本数据类型.可以使用这些类型的值来代表一些简单的状态. Java 语言的基本数据类型总共有以下8 种,下面是按照用途划分出的4 个类别: 定点类型: ...
- 【Mybatis】向MySql数据库插入千万记录 单条插入方式,用时 1h16m30s
本例代码下载:https://files.cnblogs.com/files/xiandedanteng/InsertMillionComparison20191012.rar 相对于批量插入,这种方 ...
- Android 网络请求Retrofit + RxJava
一.背景 经常看到项目用Retrofit+RxJava+RxAndroid的框架,为了看懂项目的结构.现在来了解一下,Retrofit: Retrofit是Square 公司开发的一款正对Androi ...
- matlab处理矩阵
1.提取大矩阵的一列.一行元素:一列元素: A(:,j)表示提取A矩阵的第j列全部元素一行元素: A(i,:)表示提取A矩阵的第i行元素,于是我们有,A(i, j)表示提取A矩阵的第i行第j列的元 ...
- HttpURLConnection断点下载
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.I ...