2631: tree

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 1716  Solved: 576
[Submit][Status]

Description

 一棵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的余数。

 

Input

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

Output

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

Sample Input

3 2
1 2
2 3
* 1 3 4
/ 1 1

Sample Output

4

HINT

数据规模和约定

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

  动态树编的还是不熟练,这道题的模数是刚刚爆int的(51061^2==2607225721>2147483647),如果用long long 又要TLE,所以必须用unsigned int.

  这道题涉及到动态树的路径操作,具体用法是通过make_root()access()将一个路径上所有点集中到一个splay中。

  还有一点,就是这类支持区间加,乘的题,标记应即为x*mul+plus,即先下放mul,在下放plus

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<string>
#include<queue>
using namespace std;
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
#define MAXN 110000
#define MAXT MAXN*2
#define MAXV MAXN*2
#define MAXE MAXV*2
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define lch ch[now][0]
#define rch ch[now][1]
#define plus _plus
#define MOD 51061//刚刚爆int
typedef unsigned int qword;
inline int nextInt()
{
char ch;
int x=;
bool flag=false;
do
ch=(char)getchar(),flag=(ch=='-')?true:flag;
while(ch<''||ch>'');
do x=x*+ch-'';
while (ch=(char)getchar(),ch<='' && ch>='');
return x*(flag?-:);
} int n,m;
struct Edge
{
int np;
Edge *next;
}E[MAXE],*V[MAXV];
int tope=-;
int fa[MAXT];
int depth[MAXT];
inline void addedge(int x,int y)
{
E[++tope].np=y;
E[tope].next=V[x];
V[x]=&E[tope];
}
void dfs(int now)
{
Edge *ne;
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==fa[now])continue;
fa[ne->np]=now;
depth[ne->np]=depth[now]+;
dfs(ne->np);
}
}
//------------------------Link Cut Tree------------------------
int pnt[MAXT],ch[MAXT][];
qword sum[MAXT],val[MAXT];
qword mult[MAXT],plus[MAXT];
bool flip[MAXT];
int stack[MAXT],tops=-;
int siz[MAXT];
void init()
{
int i;
for (i=;i<=n;i++)
{
pnt[i]=fa[i];
mult[i]=;
plus[i]=;
val[i]=sum[i]=;
flip[i]=false;
siz[i]=;
}
}
inline bool is_root(int now)//是splay上的根
{
return (!pnt[now]) || (ch[pnt[now]][]!=now && ch[pnt[now]][]!=now);
}
inline void up(int now)
{
sum[now]=(sum[lch]+sum[rch]+val[now])%MOD;
siz[now]=(siz[lch]+siz[rch]+)%MOD;
}
inline void reverse(int now)
{
if (!now)return;
swap(ch[now][],ch[now][]);
flip[now]^=;
}
inline void make_multiply(int now,qword v)//对于一个splay的子树加标记下放
{
mult[now]=mult[now]*v%MOD;
plus[now]=plus[now]*v%MOD;
sum[now]=sum[now]*v%MOD;
val[now]=val[now]*v%MOD;
}
inline void make_plus(int now,qword v)//同make_multiply
{
plus[now]=(plus[now]+v)%MOD;
sum[now]=(sum[now]+v*siz[now])%MOD;
val[now]=(val[now]+v)%MOD;
}
inline void down(int now)
{
if (flip[now])
{
reverse(ch[now][]);
reverse(ch[now][]);
flip[now]=false;
}
if (mult[now]!=)
{
make_multiply(ch[now][],mult[now]);
make_multiply(ch[now][],mult[now]);
mult[now]=;
}
if (plus[now])
{
make_plus(ch[now][],plus[now]);
make_plus(ch[now][],plus[now]);
plus[now]=;
}
}
inline void rotate(int now)
{
int p=pnt[now],anc=pnt[p];
if (is_root(now))throw ;
int dir=ch[p][]==now;
pnt[now]=anc;
if (!is_root(p))/**/
ch[anc][ch[anc][]==p]=now;
ch[p][-dir]=ch[now][dir];
pnt[ch[now][dir]]=p;
pnt[p]=now;
ch[now][dir]=p;
up(p);
up(now);
}
void splay(int now)
{
int x=now; while (!is_root(x))
{
stack[++tops]=x;
x=pnt[x];
}
stack[++tops]=x;
do{
down(stack[tops--]);
}while (tops>=);
if (is_root(now))return ;//先下放标记,否则access中自动接在其他点上面
while (!is_root(now))
{
int p=pnt[now],anc=pnt[p];
if (is_root(p))//注意判断的对象
{
rotate(now);
}else
{
if ((ch[anc][]==p) == (ch[p][]==now))
{
rotate(p);
rotate(now);
}else
{
rotate(now);
rotate(now);
}
}
}
}
void access(int now)//需要记忆!
{
int son=;
for (;now;now=pnt[son=now])
{
splay(now);
ch[now][]=son;
up(now);
}
// while (ch[now][0])
// now=ch[now][0];
// return now;
}
void make_root(int now)
{
access(now);
splay(now);
swap(ch[now][],ch[now][]);
reverse(ch[now][]);
reverse(ch[now][]);
//reverse(now);//注意
}
void cut(int x,int y)
{
make_root(x);
access(y);
splay(x);
ch[x][ch[x][]==y]=;
pnt[y]=;
up(x);
up(y);
}
void link(int x,int y)
{
// access(y);
splay(y);
make_root(x);
access(x);
splay(x);
pnt[x]=y;
up(y);
}
void scan(int now)
{
if (!now)return ;
down(now);
scan(lch);
printf("%d ",(int)val[now]);
scan(rch);
} int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int i;
int x,y,z;
int a,b,c,d;
scanf("%d%d",&n,&m);
for (i=;i<n;i++)
{
x=nextInt();y=nextInt();
//scanf("%d%d",&x,&y);
addedge(x,y);
addedge(y,x);
}
scanf("\n");
dfs();
init();
char opt;
for (i=;i<m;i++)
{
opt=(int)getchar();
//scanf("%c",&opt);
if (opt=='+')
{
x=nextInt();y=nextInt();z=nextInt();
//scanf("%d%d%d\n",&x,&y,&z);
z%=MOD;
make_root(x);
access(y);
splay(y);
make_plus(y,z);
}else if (opt=='-')
{
a=nextInt();b=nextInt();c=nextInt();d=nextInt();
//scanf("%d%d%d%d\n",&a,&b,&c,&d);
cut(a,b);
link(c,d);
}else if (opt=='*')
{
x=nextInt();y=nextInt();z=nextInt();
//scanf("%d%d%d\n",&x,&y,&z);
z%=MOD;
make_root(x);
access(y);
splay(y);
make_multiply(y,z);
}else if (opt=='/')
{
x=nextInt();y=nextInt();
//scanf("%d%d\n",&x,&y);
make_root(x);
access(y);
splay(y);
printf("%d\n",(int)sum[y]);
}
}
return ;
}

bzoj 2631: tree 动态树+常数优化的更多相关文章

  1. BZOJ 2631 tree 动态树(Link-Cut-Tree)

    题目大意:维护一种树形数据结构.支持下面操作: 1.树上两点之间的点权值+k. 2.删除一条边.添加一条边,保证加边之后还是一棵树. 3.树上两点之间点权值*k. 4.询问树上两点时间点的权值和. 思 ...

  2. [BZOJ 2759] 一个动态树好题

    [BZOJ 2759] 一个动态树好题 题目描述 首先这是个基环树. 然后根节点一定会连出去一条非树边.通过一个环就可以解除根的答案,然后其他节点的答案就可以由根解出来. 因为要修改\(p_i\),所 ...

  3. BZOJ 3514 (动态树)

    这两天终于基本理解了Link-Cut Tree这种神一般的东西.然后就来做这道题了. 原题是CodeChef上的.CodeChef上没有强制在线,且时限更宽松,所以似乎用莫队一样的算法把询问分组就能水 ...

  4. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  5. [BZOJ - 2631] tree 【LCT】

    题目链接:BZOJ - 2631 题目分析 LCT,像线段树区间乘,区间加那样打标记. 这道题我调了一下午. 提交之后TLE了,我一直以为是写错了导致了死循环. 于是一直在排查错误.直到.. 直到我看 ...

  6. BZOJ 2631: tree( LCT )

    LCT...略麻烦... -------------------------------------------------------------------------------- #inclu ...

  7. BZOJ 2631: tree [LCT splay区间]

    2631: tree Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 3854  Solved: 1292[Submit][Status][Discus ...

  8. bzoj 2759一个动态树好题

    真的是动态树好题,如果把每个点的父亲设成p[x],那么建出来图应该是一个环套树森林,拆掉一条边,就变成了动态树,考虑维护什么,对于LCT上每个节点,维护两组k和b,一组是他到他父亲的,一组是他LCT子 ...

  9. [BZOJ2631]tree 动态树lct

    2631: tree Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 5171  Solved: 1754[Submit][Status][Discus ...

随机推荐

  1. resin 4.0数据源的配置

    在resin 的conf 文件下有resin.xml  我们在这里能够配置数据源以及配置项目 一.配置多个数据源,多个项目共享这些数据源.也就是这些数据源配置在<host>   </ ...

  2. CPP: 跨平台生成GUID/UUID

    #ifndef XGUID_H#define XGUID_H #include <string>#include <stdio.h>#ifdef WIN32#include & ...

  3. 如何在Byte[]和String之间进行转换

    源自C#与.NET程序员面试宝典. 如何在Byte[]和String之间进行转换? 比特(b):比特只有0 1,1代表有脉冲,0代表无脉冲.它是计算机物理内存保存的最基本单元. 字节(B):8个比特, ...

  4. centos could not retrieve mirrorlist

    centos could not retrieve mirrorlist >>>>>>>>>>>>>>>> ...

  5. samba环境搭建

    1.安装samba软件 sudo apt-get install samba cifs-utils samba-common 2.创建与windows共享目录 mkdir share chmod 77 ...

  6. 网页版 treeview使用中遇到的问题

    <div class="ScrollBar" id="ItemsTree"></div> var cla = $("#Item ...

  7. 禁用UITextField复制粘贴等方法

    要实现此功能只需创建一个继承自UITextField的子类,重写以下方法即可. - (BOOL)canPerformAction:(SEL)action withSender:(id)sender{ ...

  8. java_设计模式_组合模式_Composite Pattern(2016-08-12)

    概念: 组合模式(Composite Pattern)将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性. 有时候又叫做部分-整体模式,它使我们树 ...

  9. Fast Report Data Filter

    使用Data Filter两种方式:一种是 直接在Filter 属性里写表达式 ,另外一种就是在beforePrint 事件里写方法. 今天开发时遇到了一个Filter的问题,不知道是不是fast r ...

  10. java.net.ServerSocket和java.net.Socket

    个人博客地址:http://www.cnblogs.com/wdfwolf3/ java.net.ServerSocket 1.构造函数 a.ServerSocket() 创建一个无连接的server ...