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. TR069协议向导——一个帮助你了解TR069协议的简明教程(一)

    您也能够到下面地址下载: http://download.csdn.net/source/993034 1.为什么须要TR069    随着VoIP.IPTV等越来越多IP终端设备的普及(尤其在家庭中 ...

  2. java -Xmx3550m -Xms3550m -Xmn2g -Xss128k

    java -Xmx3550m -Xms3550m -Xmn2g -Xss128k1.-Xmx3550m:设置JVM最大可用内存为3550M.2.-Xms3550m:设置JVM促使内存为3550m.此值 ...

  3. [转] Putty - 文件夹显示的蓝色太暗

    Putty SSH key的后缀为ppk 默认文件夹的颜色显示为ANSI Blue,颜色太暗. ANSI Blue : RGB(0, 0, 187) 将ANSI Blue修改为和ANSI Blue B ...

  4. Winform中修改WebBrowser控件User-Agent的方法(已经测试成功)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.W ...

  5. Migration of ASP.NET app from IIS6 to IIS7 (7.5)

    For many of us familiar problem. You developing applications under IIS6 and you're about to move the ...

  6. 免费的手机号码归属地查询API接口文档

    聚合数据手机号码归属四查询API接口,根据手机号码或手机号码的前7位,查询手机号码归属地信息,包括省份 .城市.区号.邮编.运营商和卡类型. 通过链接https://www.juhe.cn/docs/ ...

  7. ANDROID 通过监听来电去电,并弹出悬浮窗

    要监听android打电话和接电话,有一种的是通过新建一个Receiver继承自BroadcastReceiver. 还有一种也可通过PhoneStateListener来实现.今天就说说后面一种,废 ...

  8. 浅谈href 和 src的区别

    href 表示超文本引用(hypertext reference),在 link.a 等元素上.src 表示来源地址,在 img.script.iframe 等元素上.src 的内容,是页面必不可少的 ...

  9. java的真相

    所谓编译,就是把源代码“翻译”成目标代码——大多数是指机器代码——的过程.针对Java,它的目标代码不是本地机器代码,而是虚拟机代码. 编译原理里面有一个很重要的内容是编译器优化.所谓编译器优化是指, ...

  10. Android 设计随便说说之简单实践(合理组合)

    上一篇(Android 设计随便说说之简单实践(模块划分))例举了应用商店设计来说明怎么做模块划分.模块划分主要依赖于第一是业务需求,具体是怎么样的业务.应用商店则包括两个业务,就是向用户展示appl ...