「LuoguP3384」【模板】树链剖分
题目描述
如题,已知一棵包含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取模)
输入输出样例
说明
时空限制: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(重要的事情说三遍:记得取模)
题解
我也是会树剖的女人了!!!嗷嗷嗷嗷嗷嗷嗷嗷嗷嗷
模板题嘛QAQ,也没什么好讲的
剖了之后,对于操作1和2,在求lca的过程中做
对于操作3和4,直接在dfn[x]和dfn[x]+siz[x]-1上搞事就星了
其实操作1和2可以用树上前缀和水水水水水水(不对要随时询问好像布星QAQ)
#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=2e5+;
int val[MAXN];//点权
//以下建原树
struct emm{
int e,f;
}b[*MAXN];
int h[MAXN];
int tot=;
void con(int x,int y)
{
b[++tot].f=h[x];
h[x]=tot;
b[tot].e=y;
b[++tot].f=h[y];
h[y]=tot;
b[tot].e=x;
return;
}
//第一遍dfs
int d[MAXN],fa[MAXN],top[MAXN],z[MAXN],siz[MAXN];
void dfs(int x)
{
siz[x]=;
top[x]=x;
int mac=,macc=-;
for(int i=h[x];i;i=b[i].f)
if(!d[b[i].e])
{
d[b[i].e]=d[x]+;
fa[b[i].e]=x;
dfs(b[i].e);
siz[x]+=siz[b[i].e];
if(macc<siz[b[i].e]){mac=b[i].e,macc=siz[b[i].e];}
}
z[x]=mac;
top[mac]=x;
return;
}
//第二遍dfs
int q[MAXN],dfn[MAXN];
void dfss(int x)
{
q[++tot]=x;
dfn[x]=tot;
if(z[x])dfss(z[x]);
for(int i=h[x];i;i=b[i].f)
if(fa[b[i].e]==x&&b[i].e!=z[x])
dfss(b[i].e);
return;
}
//找top
int fitop(int x)
{
if(top[x]==x)return x;
return top[x]=fitop(top[x]);
}
//建树完成
int n,m,s;
long long mod;
//以下线段树
struct ahh{
int l,r;
long long v,laz;
}a[*MAXN];
void build(int i,int ll,int rr)
{
a[i].l=ll;
a[i].r=rr;
if(ll==rr){a[i].v=val[q[ll]];return;}
int mid=(ll+rr)>>;
build((i<<),ll,mid);
build(((i<<)|),mid+,rr);
a[i].v=a[(i<<)].v+a[((i<<)|)].v%mod;
return;
}
void add(int i,int ll,int rr,int k)
{
if(a[i].l==ll&&a[i].r==rr)
{a[i].laz+=k;return;}
a[i].v=(long long)a[i].v+(rr-ll+)*k%mod;
int mid=(a[i].l+a[i].r)>>;
if(rr<=mid)add((i<<),ll,rr,k);
else if(mid+<=ll)add(((i<<)|),ll,rr,k);
else {add((i<<),ll,mid,k);add(((i<<)|),mid+,rr,k);}
return;
}
void pushtag(int i)
{
if(!a[i].laz)return;
a[i].v=(long long)a[i].v+a[i].laz*(a[i].r-a[i].l+)%mod;
if(a[i].l==a[i].r){a[i].laz=;return;}
a[(i<<)].laz+=a[i].laz;
a[((i<<)|)].laz+=a[i].laz;
a[i].laz=;
return;
}
unsigned long long ans;
void find(int i,int ll,int rr)
{
pushtag(i);
if(a[i].l==ll&&a[i].r==rr){ans=(ans+a[i].v)%mod;return;}
int mid=(a[i].l+a[i].r)>>;
if(rr<=mid)find((i<<),ll,rr);
else if(ll>=mid+)find(((i<<)|),ll,rr);
else {find((i<<),ll,mid);find(((i<<)|),mid+,rr);}
return;
}
//
int main()
{
//freopen("a.in","r",stdin);
scanf("%d%d%d%lld",&n,&m,&s,&mod);
for(int i=;i<=n;++i)
scanf("%d",&val[i]);
for(int i=;i<n;++i)
{
int x,y;
scanf("%d%d",&x,&y);
con(x,y);
}
d[s]=;
dfs(s);
tot=;
dfss(s);
for(int i=;i<=n;++i)
top[i]=fitop(i);
build(,,n);
//run
for(int c=;c<=m;++c)
{
int opt;
scanf("%d",&opt);
if(opt==)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
//lca
while(top[x]!=top[y])
{
if(d[top[x]]>d[top[y]])
{
add(,dfn[top[x]],dfn[x],z);
x=fa[top[x]];
}
else
{
add(,dfn[top[y]],dfn[y],z);
y=fa[top[y]];
}
}
if(d[x]>d[y])add(,dfn[y],dfn[x],z);
else add(,dfn[x],dfn[y],z);
}
else if(opt==)
{
int x,y;
scanf("%d%d",&x,&y);
ans=;
while(top[x]!=top[y])
{
if(d[top[x]]>d[top[y]])
{
find(,dfn[top[x]],dfn[x]);
ans%=mod;
x=fa[top[x]];
}
else
{
find(,dfn[top[y]],dfn[y]);
ans%=mod;
y=fa[top[y]];
}
}
if(d[x]>d[y])find(,dfn[y],dfn[x]);
else find(,dfn[x],dfn[y]);
printf("%lld\n",ans%mod);
}
else if(opt==)
{
int x,z;
scanf("%d%d",&x,&z);
add(,dfn[x],dfn[x]+siz[x]-,z);
}
else
{
int x;
scanf("%d",&x);
ans=;
find(,dfn[x],dfn[x]+siz[x]-);
printf("%lld\n",ans%mod);
}
}
return ;
}
「LuoguP3384」【模板】树链剖分的更多相关文章
- 「POJ3237」Tree(树链剖分)
题意 给棵n个点的树.边有边权然后有三种操作 1.CHANGE i v 将编号为i的边权变为v 2.NEGATE a b 将a到b的所有边权变为相反数. 3.QUERY a b 查询a b路径的最大边 ...
- 「HNOI2015」开店(树链剖分, 主席树)
/* 考虑将所求的值拆分 记每个点到根的路径长度为dis_i, 那么我们要求的就是\sum_{i = l} ^ r dis_i + dis[u] * (r - l + 1) - 2\sum_{i = ...
- luoguP3384 [模板]树链剖分
luogu P3384 [模板]树链剖分 题目 #include<iostream> #include<cstdlib> #include<cstdio> #inc ...
- [luogu P3384] [模板]树链剖分
[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...
- [洛谷P3384] [模板] 树链剖分
题目传送门 显然是一道模板题. 然而索引出现了错误,狂wa不止. 感谢神犇Dr_J指正.%%%orz. 建线段树的时候,第44行. 把sum[p]=bv[pos[l]]%mod;打成了sum[p]=b ...
- loj#6073. 「2017 山东一轮集训 Day5」距离(树链剖分 主席树)
题意 题目链接 Sol 首先对询问差分一下,我们就只需要统计\(u, v, lca(u, v), fa[lca(u, v)]\)到根的路径的贡献. 再把每个点与\(k\)的lca的距离差分一下,则只需 ...
- 模板 树链剖分BFS版本
//点和线段树都从1开始 //边使用vector vector<int> G[maxn]; ],num[maxn],iii[maxn],b[maxn],a[maxn],top[maxn], ...
- P3384 [模板] 树链剖分
#include <bits/stdc++.h> using namespace std; typedef long long ll; int n, m, rt, mod, cnt, to ...
- 树链剖分详解(洛谷模板 P3384)
洛谷·[模板]树链剖分 写在前面 首先,在学树链剖分之前最好先把 LCA.树形DP.DFS序 这三个知识点学了 emm还有必备的 链式前向星.线段树 也要先学了. 如果这三个知识点没掌握好的话,树链剖 ...
- 『题解』洛谷P3384 【模板】树链剖分
Problem Portal Portal1: Luogu Description 如题,已知一棵包含\(N\)个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作\(1\): ...
随机推荐
- Can't connect to X11 window server using 'localhost:0.0' 的解决
Can't connect to X11 window server using 'localhost:0.0' 的解决 http://lufei-99999.blog.163.com/blog/st ...
- jpaRepository findById()数据库有数据却为null
oracle中的char类型用空格自动将字段补成指定的长度, 而varchar2类型不会.大部分情况下设计表字段类型都是varchar2,今天被char坑了一次, findById()始终为空..
- Heavy Transportation(最短路)
poj 1797 ——Heavy Transportation 思路: 这道题我们可以采用类似于求最短路径的方法,用一种新的“松弛操作”去取代原本的方法. 我们可以记录d[u]为运送货物到点j时最大可 ...
- 【gradle】mac下 gradle默认本地仓库位置
gradle默认会把包缓存到用户目录的.gradle目录下,如果你打开.gradle\caches\modules-2\files-2.1,你会发现很多的jar包.mac上的话 ,也就是在/Users ...
- 【Todo】Java类型转换总结
参考 http://www.cnblogs.com/lwbqqyumidi/p/3700164.html 这篇文章也可以对照着看:http://www.360doc.com/content/10/09 ...
- [反汇编练习] 160个CrackMe之023
[反汇编练习] 160个CrackMe之023. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...
- Linux驱动基础开发
Linux 内核配置机制(make menuconfig.Kconfig.makefile)讲解 前面我们介绍模块编程的时候介绍了驱动进入内核有两种方式:模块和直接编译进内核,并介绍了模块的一种编译方 ...
- centos 複製時顯示進度的指令 pv
Pipe Viewer 的简称pv:意思是通过管道显示数据处理进度的信息.这些信息包括已经耗费的时间,完成的百分比(通过进度条显示),当前的速度,全部传输的数据,以及估计剩余的时间. yum inst ...
- 亲测linux上安装svn
方法一: 1.wget http://subversion.tigris.org/downloads/subversion-1.6.1.tar.gz2.wget http://subversion.t ...
- 【转载】Open Live Writer 安装
Open Live Writer来源 Windows Live Writer在2012年就停止了更新,Open Live Writer是由Windows Live WriterWriter更名而来,是 ...