题目描述

如题,已知一棵包含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 ;
}

洛谷P3384 【模板】树链剖分的更多相关文章

  1. [洛谷P3384] [模板] 树链剖分

    题目传送门 显然是一道模板题. 然而索引出现了错误,狂wa不止. 感谢神犇Dr_J指正.%%%orz. 建线段树的时候,第44行. 把sum[p]=bv[pos[l]]%mod;打成了sum[p]=b ...

  2. [luogu P3384] [模板]树链剖分

    [luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...

  3. 洛谷P3979 遥远的国度 树链剖分+分类讨论

    题意:给出一棵树,这棵树每个点有权值,然后有3种操作.操作一:修改树根为rt,操作二:修改u到v路径上点权值为w,操作三:询问以rt为根x子树的最小权值. 解法:如果没有修改树根操作那么这题就是树链剖 ...

  4. 洛谷 P4114 Qtree1 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例: 输出样例: 说明 说明 思路 Change Query AC代码 总结 题面 题目链接 P4114 Qt ...

  5. 洛谷.4114.Qtree1(树链剖分)

    题目链接 模板题都错了这么多次.. //边权赋到点上 树剖模板 //注意LCA.链的顶端不能统计到答案! #include <cstdio> #include <cctype> ...

  6. 洛谷3384&bzoj1036树链剖分

    值得注意的是: 一个点的子树是存在一起的...也就是说我们修改子树的时候只用... /********************************************************* ...

  7. P3384 [模板] 树链剖分

    #include <bits/stdc++.h> using namespace std; typedef long long ll; int n, m, rt, mod, cnt, to ...

  8. luoguP3384 [模板]树链剖分

    luogu P3384 [模板]树链剖分 题目 #include<iostream> #include<cstdlib> #include<cstdio> #inc ...

  9. 【Luogu P3384】树链剖分模板

    树链剖分的基本思想是把一棵树剖分成若干条链,再利用线段树等数据结构维护相关数据,可以非常暴力优雅地解决很多问题. 树链剖分中的几个基本概念: 重儿子:对于当前节点的所有儿子中,子树大小最大的一个儿子就 ...

  10. 模板 树链剖分BFS版本

    //点和线段树都从1开始 //边使用vector vector<int> G[maxn]; ],num[maxn],iii[maxn],b[maxn],a[maxn],top[maxn], ...

随机推荐

  1. 去哪儿数据VS美团数据

    介绍 之前在去哪儿做数据RD,今年来到美团做数据RD,碰巧都是门票方向(现在去哪儿叫度假,美团叫境内),下面都是基于这两个部门的对比 相同点 都有独立的数据团队,老大都重视数据,主要开发语言都是SQL ...

  2. jetty9.4缓存文件目录自定义

    jetty9.4安装包解压之后,有几个修改的地方和jetty7.6有不同,需要单独注意一下: 1. 端口设置 端口设置在${jetty_home}/start.ini中 2. 缓存文件生成目录 项目通 ...

  3. 面试汇总——知道什么是同源策略吗?那怎么解决跨域问题?知道 JSONP 原理吗?

    本文是面试汇总分支——知道什么是同源策略吗?那怎么解决跨域问题?知道 JSONP 原理吗?. 同源策略 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能, ...

  4. 关于inodes占用100%解决方法

    df -i; 发现inode节点占满: 这个时候如果不知道哪儿节点占用多可以用下边的脚本进行检查,查看到底哪个目录下面的文件最多: for i in /*; do echo $i; find $i | ...

  5. Linux安装NET CORE

    Linux安装.NET CORE 1.Add the dotnet apt-get feed 为了在Ubuntu或Linux Mint上安装.NET,您需要首先设置托管所需软件包的apt-get fe ...

  6. NodeJs之fs

    NodeJs版本:4.4.4 fs的实用方法 查看文件信息(fs.stat) 定义:fs.stat(path, callback) var fs = require('fs'); fs.stat('t ...

  7. 关于web项目创建后WEB-INF下面没有出现web.xml的解决方法

    提供两种解决方案: 第一种:创建完项目后,需要手动创建出web.xml 第一步:选取创建的项目名称右击 第二步:eclipse的同学找到 java EE Tools 中的 下图画圈部分.  MyEcl ...

  8. WireShark如何抓取本地localhost的包

    今天将自己的电脑既作为客户端又作为服务端进行一个程序的测试,想着用WireShark来抓包分析一下问题,但由于WireShark只能抓取经过电脑网卡的包,由于我是使用localhost或者127.0. ...

  9. Swagger UI 与SpringMVC的整合

    关于 Swagger Swagger能成为最受欢迎的REST APIs文档生成工具之一,有以下几个原因: Swagger 可以生成一个具有互动性的API控制台,开发者可以用来快速学习和尝试API. S ...

  10. Spring-Cloud-Ribbon学习笔记(一):入门

    简介 Spring Cloud Ribbon是一个基于Http和TCP的客户端负载均衡工具,它是基于Netflix Ribbon实现的.它不像服务注册中心.配置中心.API网关那样独立部署,但是它几乎 ...