题目描述

如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

输入输出格式

输入格式:

第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。

接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)

接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:

操作1: 1 x y z

操作2: 2 x y

操作3: 3 x z

操作4: 4 x

输出格式:

输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)

输入输出样例

输入样例#1:

5 5 2 24
7 3 7 8 0
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3
输出样例#1:

2
21

说明

时空限制:1s,128M

数据规模:

对于30%的数据: N≤10,M≤10

对于70%的数据: N≤10^3,M≤10^3

对于100%的数据: N≤10^5,M≤10^5

( 其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233 )

样例说明:

树的结构如下:

各个操作如下:

故输出应依次为2、21(重要的事情说三遍:记得取模)

 #include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 100007
using namespace std;
long long read()
{
long long x=,f=;
char ch=getchar();
while(ch<''||ch>'')
{
if(ch=='-')
f=-;
ch=getchar();
}
while(ch>=''&&ch<='')
{
x=x*+ch-'';
ch=getchar();
}
return x*f;
}
int n,m,num,root,p,opt,x,y,z,cnt;
int head[maxn*],a[maxn],son[maxn],fa[maxn],deep[maxn],size[maxn],top[maxn],pos[maxn],data[maxn],in[maxn],out[maxn];
struct node
{
int v,nxt;
} e[maxn];
void add(int u,int v)
{
e[++num].v=v;
e[num].nxt=head[u];
head[u]=num;
e[++num].v=u;
e[num].nxt=head[v];
head[v]=num;
}
struct NODE
{
int l,r,sum,flag;
} tree[maxn*];
void dfs(int now)
{
size[now]=;
for(int i=head[now]; i; i=e[i].nxt)
if(fa[now]!=e[i].v)
{
fa[e[i].v]=now;
deep[e[i].v]=deep[now] + ;
dfs(e[i].v);
size[now]+=size[e[i].v];
if(size[son[now]]<size[e[i].v])
son[now]=e[i].v;
}
}
void DFS(int now,int num)
{
top[now]=num;
pos[now]=++cnt;
in[now]=cnt;
data[cnt]=a[now];
if(son[now])
DFS(son[now],num);
for(int i=head[now]; i; i=e[i].nxt)
if(fa[now]!=e[i].v&&e[i].v!=son[now])
DFS(e[i].v,e[i].v);
out[now]=cnt;
}
void build(int now,int l,int r)
{
tree[now].l=l;
tree[now].r=r;
tree[now].flag=;
if(l==r)
{
tree[now].sum=data[l];
return ;
}
int mid=(l+r)>>;
build(now<<,l,mid);
build(now<<|,mid+,r);
tree[now].sum=tree[now<<].sum+tree[now<<|].sum;
}
void down(int now)
{
if(tree[now].l==tree[now].r)
{
tree[now].flag=;
return ;
}
tree[now<<].flag+=tree[now].flag;
tree[now<<|].flag+=tree[now].flag;
tree[now<<].sum=(tree[now<<].sum+tree[now].flag*(tree[now<<].r-tree[now<<].l+))%p;
tree[now<<|].sum=(tree[now<<|].sum+tree[now].flag*(tree[now<<|].r-tree[now<<|].l+))%p;
tree[now].flag=;
}
void change(int now,int l,int r,int f)
{
while(tree[now].flag)
down(now);
if(tree[now].l>r||tree[now].r<l)
return ;
if(tree[now].l>=l&&tree[now].r<=r)
{
tree[now].flag=f;
(tree[now].sum+=f*(tree[now].r-tree[now].l+))%=p;
return ;
}
change(now<<,l,r,f);
change(now<<|,l,r,f);
tree[now].sum=(tree[now<<].sum+tree[now<<|].sum)%p;
}
int query(int now,int l,int r)
{
while(tree[now].flag) down(now);
if(tree[now].l>r||tree[now].r<l)
return ;
if(tree[now].l>=l&&tree[now].r<=r)
return tree[now].sum;
return (query(now<<,l,r)+query(now<<|,l,r))%p;
}
void add1()
{
x=read(),y=read(),z=read(),z%=p;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
swap(x,y);
change(,pos[top[x]],pos[x],z);
x=fa[top[x]];
}
if(deep[x]<deep[y])
swap(x,y);
change(,pos[y],pos[x],z);
}
void add2()
{
x=read(),z=read(),z%=p;
change(,in[x],out[x],z);
}
void query1()
{
x=read(),y=read();
int ans=;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
swap(x,y);
ans=(ans+query(,pos[top[x]],pos[x]))%p;
x=fa[top[x]];
}
if(deep[x]<deep[y])
swap(x,y);
(ans+=query(,pos[y],pos[x]))%=p;
printf("%d\n",ans);
}
void query2()
{
x=read();
int ans=;
(ans=query(,in[x],out[x]))%=p;
printf("%d\n",ans);
}
int main()
{
n=read(),m=read(),root=read(),p=read();
for(int i=; i<=n; ++i)
a[i]=read(),a[i]%=p;
for(int i=,a,b; i<n; ++i)
a=read(),b=read(),add(a,b);
dfs(root);
DFS(root,root);
build(,,n);
while(m--)
{
opt=read();
if(opt==)
add1();
else if(opt==)
add2();
else if(opt==)
query1();
else
query2();
}
return ;
}

最新文章

  1. ArcGIS删除部分数据后全图范围不正确
  2. SharePoint ribbon icons disappeared(网站顶部Top bar 齿轮图标,以及编辑模式下Ribbon中Icon消失)
  3. 【HDOJ】3208 Integer’s Power
  4. java比.net优美的一个小地方
  5. 函数 resize和reserve的区别
  6. Java NIO流 -- 缓冲区(Buffer,ByteBuffer)
  7. Qt编程之qrc文件的链接
  8. EBS-PAC成本更新事务处理
  9. Hibernate.cfg.xml 主配置
  10. android-iconify 使用详解
  11. (3两个例子)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  12. Django--基本篇:项目结构与设计模式(MVC)
  13. webpack-dev-server运行时报错
  14. KubeCon + CloudNativeCon论坛2019上海
  15. Oracle 11g ogg单表初始化步骤
  16. winsock 编程(简单客户&amp;服务端通信实现)
  17. ZZNU 2098 Drink coffee(差分+树状数组)
  18. NET Core中使用Angular2的Token base身份认证
  19. (水题) Div 3 -- SGU -- 105
  20. SYS远程连接出错ORA-01031:Insufficient privileges

热门文章

  1. Linux 添加开机启动项的两种方法
  2. Clion使用MinGW编译好的boost库
  3. R语言学习-set.seed()
  4. 微表面分布函数(Microfacet Distribution Function)确切含义
  5. 【JAVA面试】java面试题整理(4)
  6. [elk]elasticsearch实现冷热数据分离
  7. 物联网架构成长之路(30)-Spring Boot Admin微服务WebUI监控
  8. 设置GRUB密码以防止单用户模式下root密码被恶意更改
  9. 常用xpath选择器和css选择器总结
  10. 【OCR技术系列之六】文本检测CTPN的代码实现