题目描述

 一棵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行,每行描述一个操作

输出

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

样例输入

3 2
1 2
2 3
* 1 3 4
/ 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

LCT,splay每个点维护子树和,单点权值和两个区间修改标记,注意加法和乘法运算顺序即可。开unsigned int即可,开longlong可能会T。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll unsigned int
using namespace std;
int n,m;
int x,y,z,w;
int mod=51061;
char ch[2];
int f[100010];
int s[100010][2];
int st[100010];
int r[100010];
int size[100010];
ll sum[100010];
ll val[100010];
ll a[100010];
ll b[100010];
int get(int rt)
{
return rt==s[f[rt]][1];
}
void change(int rt,int x,int y)
{
if(!rt)
{
return ;
}
sum[rt]=(sum[rt]*x+y*size[rt])%mod;
val[rt]=(val[rt]*x+y)%mod;
a[rt]=(a[rt]*x+y)%mod;
b[rt]=(b[rt]*x)%mod;
}
void pushup(int rt)
{
sum[rt]=(sum[s[rt][0]]+sum[s[rt][1]]+val[rt])%mod;
size[rt]=(size[s[rt][0]]+size[s[rt][1]]+1)%mod;
}
void pushdown(int rt)
{
if(r[rt])
{
swap(s[rt][0],s[rt][1]);
r[s[rt][0]]^=1;
r[s[rt][1]]^=1;
r[rt]^=1;
}
int x=a[rt];
int y=b[rt];
a[rt]=0;
b[rt]=1;
if(x!=0||y!=1)
{
change(s[rt][0],y,x);
change(s[rt][1],y,x);
}
}
int is_root(int rt)
{
return s[f[rt]][0]!=rt&&s[f[rt]][1]!=rt;
}
void rotate(int rt)
{
int fa=f[rt];
int anc=f[fa];
int k=get(rt);
if(!is_root(fa))
{
s[anc][fa==s[anc][1]]=rt;
}
s[fa][k]=s[rt][k^1];
f[s[fa][k]]=fa;
s[rt][k^1]=fa;
f[fa]=rt;
f[rt]=anc;
pushup(fa);
pushup(rt);
}
void splay(int rt)
{
int top=0;
st[++top]=rt;
for(int i=rt;!is_root(i);i=f[i])
{
st[++top]=f[i];
}
for(int i=top;i>=1;i--)
{
pushdown(st[i]);
}
for(int fa;!is_root(rt);rotate(rt))
{
if(!is_root(fa=f[rt]))
{
rotate(get(rt)==get(fa)?fa:rt);
}
}
}
void access(int rt)
{
for(int x=0;rt;x=rt,rt=f[rt])
{
splay(rt);
s[rt][1]=x;
pushup(rt);
}
}
void reverse(int rt)
{
access(rt);
splay(rt);
r[rt]^=1;
}
void split(int x,int y)
{
reverse(x);
access(y);
splay(y);
}
void link(int x,int y)
{
reverse(x);
f[x]=y;
}
void cut(int x,int y)
{
reverse(x);
access(y);
splay(y);
s[y][0]=f[x]=0;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
size[i]=val[i]=sum[i]=b[i]=1;
}
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
link(x,y);
}
while(m--)
{
scanf("%s",ch);
scanf("%d%d",&x,&y);
if(ch[0]=='+')
{
scanf("%d",&z);
split(x,y);
change(y,1,z);
}
else if(ch[0]=='-')
{
scanf("%d%d",&w,&z);
cut(x,y);
link(w,z);
}
else if(ch[0]=='*')
{
scanf("%d",&z);
split(x,y);
change(y,z,0);
}
else if(ch[0]=='/')
{
split(x,y);
printf("%d\n",sum[y]);
}
}
}

BZOJ2631tree——LCT的更多相关文章

  1. Link-Cut Tree(LCT)&TopTree讲解

    前言: Link-Cut Tree简称LCT是解决动态树问题的一种数据结构,可以说是我见过功能最强大的一种树上数据结构了.在此与大家分享一下LCT的学习笔记.提示:前置知识点需要树链剖分和splay. ...

  2. 一堆LCT板子

    搞了一上午LCT,真是累死了-- 以前总觉得LCT高大上不好学不好打,今天打了几遍感觉还可以嘛= =反正现在的水平应付不太难的LCT题也够用了,就这样好了,接下来专心搞网络流. 话说以前一直YY不出来 ...

  3. 动态树之LCT(link-cut tree)讲解

    动态树是一类要求维护森林的连通性的题的总称,这类问题要求维护某个点到根的某些数据,支持树的切分,合并,以及对子树的某些操作.其中解决这一问题的某些简化版(不包括对子树的操作)的基础数据结构就是LCT( ...

  4. 在此为LCT开一个永久的坑

    其实我连splay都还不怎么会. 今天先抄了黄学长的bzoj2049,以后一定要把它理解了. 写LCT怎么能不%数据结构大神yeweining呢?%%%chrysanthemums  %%%切掉大森林 ...

  5. 【BZOJ2157】旅游 LCT

    模板T,SB的DMoon..其实样例也是中国好样例...一开始不会复制,yangyang:找到“sample input”按住shift,按page down.... #include <ios ...

  6. 【BZOJ3669】[Noi2014]魔法森林 LCT

    终于不是裸的LCT了...然而一开始一眼看上去这是kruskal..不对,题目要求1->n的路径上的每个点的两个最大权值和最小,这样便可以用LCT来维护一个最小生成路(瞎编的...),先以a为关 ...

  7. 【BZOJ1180】: [CROATIAN2009]OTOCI & 2843: 极地旅行社 LCT

    竟然卡了我....忘记在push_down先下传父亲的信息了....还有splay里for():卡了我10min,但是双倍经验还是挺爽的,什么都不用改. 感觉做的全是模板题,太水啦,不能这么水了... ...

  8. 【BZOJ3282】Tree LCT

    1A爽,感觉又对指针重怀信心了呢= =,模板题,注意单点修改时splay就好,其实按吾本意是没写的也A了,不过应该加上能更好维护平衡性. ..还是得加上好= = #include <iostre ...

  9. BZOJ2888 资源运输(LCT启发式合并)

    这道题目太神啦! 我们考虑他的每一次合并操作,为了维护两棵树合并后树的重心,我们只好一个一个的把节点加进去.那么这样一来看上去似乎就是一次操作O(nlogn),但是我们拥有数据结构的合并利器--启发式 ...

随机推荐

  1. Photoshop 基础二 快捷键

    1.取消选区:Ctrl + D 2.反选: Shift + F7 3.复位调板:窗口-工作区-复位调板位置 4.图像的缩放: Ctrl.+.- 5.用前景色填充:Ctrl + Delete 6.用背景 ...

  2. ubuntu14.04终端分屏terminator的安装使用与配置

    安装 terminator 软件 . sudo apt-get install terminator 这个终端程序可以分屏,常用操作快捷键如下: Ctrl+Shift+O Split terminal ...

  3. Git使用—第二讲

    前面我们学习了Git最基本的用法,包括安装Git.创建代码仓库,以及提交本地代码.下面我们将学习Git更多的使用技巧,在开始之前,我们先给一个项目创建代码仓库,这里选择在ProviderTest项目中 ...

  4. python条件、循环语句

    既然讲到语句,那先说明一下语句块.语句块不是一种语句,是一组语句.在条件为真时执行或者多次的一组语句.主要注意其格式,用冒号来标识语句块的开始,块中每行缩进相同的量,一般4个空格(tab字符位置为8个 ...

  5. 在项目中,多个方法会调用相同的sql语句,怎么解决各个方法的不同sql查询,解决冲突。

    公司的代码中sql语句,可能会被多个方法进行调用,但是有的方法会关联到别的表,这样的话,如果修改不当,那么同样调用该sql语句的方法,会出现报错. 最近做的公司的一个功能,就出现这样一个问题,虽然本功 ...

  6. bat无故报错打印混乱的解决

    1. 下面语句加了一个无意义的ping操作.不加的时候经常报错,报操作数不是数字,实际上打印发现NOW值和格式并没有错误.怀疑是下面操作数太多了,而执行速度又太快,导致执行时总是很容易出错.通过增加一 ...

  7. CF1039D You Are Given a Tree 根号分治、二分、贪心

    传送门 似乎直接做不太好做-- 当你不会做的时候就可以考虑根号算法了(或许是这样的 考虑如果只有一个询问如何计算答案. 显然是可以贪心的,思路与NOIP2018D1T3是相同的.每一个点向上传一条链, ...

  8. Perhaps you are running on a JRE rather than a JDK

    在Eclipse中跑maven项目时,出现上面的问题: 1.有可能你的环境变量配置是在jre上面的,所以你要检查一下你配置文件,PATH和CLASSPATH都要检查 2.eclipse默认是跑在jre ...

  9. Python爬虫利器二之Beautiful Soup的用法

    上一节我们介绍了正则表达式,它的内容其实还是蛮多的,如果一个正则匹配稍有差池,那可能程序就处在永久的循环之中,而且有的小伙伴们也对写正则表达式的写法用得不熟练,没关系,我们还有一个更强大的工具,叫Be ...

  10. P4099 [HEOI2013]SAO

    P4099 [HEOI2013]SAO 贼板子有意思的一个题---我()竟然没看题解 有一张连成树的有向图,球拓扑序数量. 树形dp,设\(f[i][j]\)表示\(i\)在子树中\(i\)拓扑序上排 ...