题目描述

如题,已知一棵包含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<=1000,M<=1000

对于100%的数据:N<=100000,M<=100000

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

样例说明:

树的结构如下:

各个操作如下:

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

思路:

  裸树剖;

来,上代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> #define maxn 100001
#define LL long long int using namespace std; struct EdgeType {
LL to,next;
};
struct EdgeType edge[maxn<<]; struct TreeNodeType {
LL l,r,dis,mid,flag;
};
struct TreeNodeType tree[maxn<<]; LL if_z,tree_num,tree_dis[maxn],deep[maxn],cnt;
LL f[maxn],n,m,s,p,dis[maxn],flag[maxn],Enum;
LL size[maxn],end[maxn],belong[maxn],head[maxn]; char Cget; inline void read_int(LL &now)
{
now=,if_z=,Cget=getchar();
while(Cget>''||Cget<'')
{
if(Cget=='-') if_z=-;
Cget=getchar();
}
while(Cget>=''&&Cget<='')
{
now=now*+Cget-'';
Cget=getchar();
}
now*=if_z;
} inline void edge_add(LL from,LL to)
{
edge[++Enum].to=from,edge[Enum].next=head[to],head[to]=Enum;
edge[++Enum].to=to,edge[Enum].next=head[from],head[from]=Enum;
} inline void tree_up(LL now)
{
tree[now].dis=tree[now<<].dis+tree[now<<|].dis;
} void tree_build(LL now,LL l,LL r)
{
tree[now].l=l,tree[now].r=r;
if(l==r)
{
tree[now].dis=tree_dis[++tree_num];
return ;
}
tree[now].mid=(tree[now].l+tree[now].r)>>;
tree_build(now<<,l,tree[now].mid);
tree_build(now<<|,tree[now].mid+,r);
tree_up(now);
} inline void tree_down(LL now)
{
if(tree[now].l==tree[now].r) return ;
tree[now<<].dis+=(tree[now<<].r-tree[now<<].l+)*tree[now].flag;
tree[now<<].flag+=tree[now].flag;
tree[now<<|].dis+=(tree[now<<|].r-tree[now<<|].l+)*tree[now].flag;
tree[now<<|].flag+=tree[now].flag;
tree[now].flag=;
} void tree_change(LL now,LL l,LL r,LL x)
{
if(tree[now].l==l&&tree[now].r==r)
{
tree[now].dis+=(r-l+)*x;
tree[now].flag+=x;
return ;
}
if(tree[now].flag) tree_down(now);
if(l>tree[now].mid) tree_change(now<<|,l,r,x);
else if(r<=tree[now].mid) tree_change(now<<,l,r,x);
else
{
tree_change(now<<,l,tree[now].mid,x);
tree_change(now<<|,tree[now].mid+,r,x);
}
tree_up(now);
} LL tree_query(LL now,LL l,LL r)
{
if(tree[now].l==l&&tree[now].r==r)
{
return tree[now].dis;
}
if(tree[now].flag) tree_down(now);
tree_up(now);
if(l>tree[now].mid) return tree_query(now<<|,l,r);
else if(r<=tree[now].mid) return tree_query(now<<,l,r);
else return tree_query(now<<,l,tree[now].mid)+tree_query(now<<|,tree[now].mid+,r);
} void search(LL now,LL fa)
{
LL pos=cnt++;
deep[now]=deep[fa]+,f[now]=fa;
for(LL i=head[now];i;i=edge[i].next)
{
if(edge[i].to==fa) continue;
search(edge[i].to,now);
}
size[now]=cnt-pos;
} void search_(LL now,LL chain)
{
belong[now]=chain,flag[now]=++cnt;
tree_dis[flag[now]]=dis[now];
LL pos=;
for(LL i=head[now];i;i=edge[i].next)
{
if(flag[edge[i].to]!=) continue;
if(size[edge[i].to]>size[pos]) pos=edge[i].to;
}
if(pos!=) search_(pos,chain);
for(LL i=head[now];i;i=edge[i].next)
{
if(flag[edge[i].to]!=) continue;
search_(edge[i].to,edge[i].to);
}
end[now]=cnt;
} inline void solve_change(LL x,LL y,LL z)
{
while(belong[x]!=belong[y])
{
if(deep[belong[x]]<deep[belong[y]]) swap(x,y);
tree_change(,flag[belong[x]],flag[x],z);
x=f[belong[x]];
}
if(deep[x]<deep[y]) swap(x,y);
tree_change(,flag[y],flag[x],z);
} inline LL solve_query(LL x,LL y)
{
LL ans=;
while(belong[x]!=belong[y])
{
if(deep[belong[x]]<deep[belong[y]]) swap(x,y);
ans=(ans+tree_query(,flag[belong[x]],flag[x]))%p;
x=f[belong[x]];
}
if(deep[x]<deep[y]) swap(x,y);
ans=(ans+tree_query(,flag[y],flag[x]))%p;
return ans;
} int main()
{
read_int(n),read_int(m),read_int(s),read_int(p);
for(LL i=;i<=n;i++) read_int(dis[i]);
LL type,from,to,cur;
for(LL i=;i<n;i++)
{
read_int(from),read_int(to);
edge_add(from,to);
}
search(s,),cnt=,search_(s,s);
cnt=,tree_build(,,n);
for(LL i=;i<=m;i++)
{
read_int(type);
if(type==)
{
read_int(from),read_int(to),read_int(cur);
solve_change(from,to,cur);
}
if(type==)
{
read_int(from),read_int(to);
printf("%d\n",solve_query(from,to)%p);
}
if(type==)
{
read_int(from),read_int(to);
tree_change(,flag[from],end[from],to);
}
if(type==)
{
read_int(from);
printf("%d\n",tree_query(,flag[from],end[from])%p);
}
}
return ;
}

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

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

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

  2. luoguP3384 [模板]树链剖分

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

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

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

  4. 模板 树链剖分BFS版本

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

  5. AC日记——红色的幻想乡 洛谷 P3801

    红色的幻想乡 思路: 线段树+容斥原理: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #de ...

  6. AC日记——无线网络发射器选址 洛谷 P2038

    题目描述 随着智能手机的日益普及,人们对无线网的需求日益增大.某城市决定对城市内的公共场所覆盖无线网. 假设该城市的布局为由严格平行的129 条东西向街道和129 条南北向街道所形成的网格状,并且相邻 ...

  7. AC日记——小A的糖果 洛谷七月月赛

    小A的糖果 思路: for循环贪心: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #defi ...

  8. AC日记——矩阵取数游戏 洛谷 P1005

    矩阵取数游戏 思路: dp+高精: 代码: #include <bits/stdc++.h> using namespace std; #define ll long long struc ...

  9. AC日记——妖梦拼木棒 洛谷 P3799

    妖梦拼木棒 思路: 神特么题: 代码: #include <bits/stdc++.h> using namespace std; #define mod 1000000007LL int ...

随机推荐

  1. HDU 4005 The war 双连通分量 缩点

    题意: 有一个边带权的无向图,敌人可以任意在图中加一条边,然后你可以选择删除任意一条边使得图不连通,费用为被删除的边的权值. 求敌人在最优的情况下,使图不连通的最小费用. 分析: 首先求出边双连通分量 ...

  2. TCP/IP网络编程之多种I/O函数

    send和recv函数 在之前的学习中,我们在不少示例中用到send和recv这两个函数,但一直没有详细解释过着两个函数中每个参数的含义.本节将介绍Linux平台下的send&recv函数 # ...

  3. Spring框架配置beans.xml

    Spring学习笔记(一) 一.Spring 框架 Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的.框架的主要优势之一就是其分层架构,分层架构允许您选择使用哪一个组件,同时为 ...

  4. Spring整合Hibernate与Struts

    整合S2SH 一.导入jar包 Spring jar包 Hibernate jar包 Struts2 jar包 以上就是整合需要的所有jar包,当然其中有重复的包,(对比之后去掉版本低的就可以了,还有 ...

  5. Log4j官方文档翻译(六、日志的级别)

    org.apache.log4j.Level 类提供了下面几种日志级别,你也可以通过继承这些类,自定义级别 ALL 所有日志级别都包括 DEBUG 指定信息事件的粒度是DEBUG,在调试应用的时候会有 ...

  6. EasyUI序列化提交学习总结

    jquery easyui将form表单元素的值序列化成对象 form表单 <form id="ff"> <input type="text" ...

  7. Java面试题之如何防止重复下单问题?

    在电商环境下,如何防止重复下单这种问题,很常见,并且解决方案有很多种,我经过百度,并且加入我的理解唠嗑几句: 流程: ①当进入商品详情页时,去生成一个全局唯一ID(可用雪花算法): ②将这个全局唯一I ...

  8. 【bzoj3894】文理分科 网路流

    [bzoj3894]文理分科 2015年3月25日3,4002 Description  文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠 结过)  小P所在的班级要进行文理分科.他的班 ...

  9. 第一个nodejs爬虫:爬取豆瓣电影图片

    第一个nodejs爬虫:爬取豆瓣电影图片存入本地: 首先在命令行下 npm install request cheerio express -save; 代码: var http = require( ...

  10. NodeJS学习(1)--- 安装配置介绍

    Node.js 安装配置 本章节我们将向大家介绍在window和Linux上安装Node.js的方法. 本安装教程以Node.js v6.10.1 LTS(长期支持版本)版本为例. Node.js安装 ...