「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\): ...
随机推荐
- AC日记——草地排水 codevs 1993
1993 草地排水 USACO 时间限制: 2 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 在农夫约翰的农场上,每 ...
- (46)C#注册表及读写
启动注册表:regedit 结构: 注册表一共有7个配置单元用regedit只能看到5个 HKEY_CLASSES_ROOT 包含系统上文件类型的细节(.txt,.doc)等.以及使用那些应用程序可以 ...
- T1164 统计数字 codevs
http://codevs.cn/problem/1164/ 题目描述 Description [问题描述]某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*109).已知不 ...
- ssh的安装和使用
1.ssh的安装 服务器端:sudo apt-get install openssh-serve 客户端:sudo apt-get install openssh-client 2.ssh的操作 查看 ...
- CS Academy #32 G
题意: 分析: 考虑如何求方案数 dp[i][j]表示i个数字的和为j的方案数,这是个经典问题,转移有两种,一个是填一个数字1,一个是整体加1 然后这个问题并不是求方案数,而是求对应的权值和 我们很容 ...
- 基于Android的远程视频监控系统(含源码)
基本过程是android作为socket客户端将采集到的每一帧图像数据发送出去,PC作为服务器接收并显示每一帧图像实现远程监控.图片如下(后来PC端加了个拍照功能)... (PS.刚学android和 ...
- [转]java中的字符串相关知识整理
字符串为什么这么重要 写了多年java的开发应该对String不陌生,但是我却越发觉得它陌生.每学一门编程语言就会与字符串这个关键词打不少交道.看来它真的很重要. 字符串就是一系列的字符组合的串,如果 ...
- Mysql学习之十二:JDBC连接数据库之DriverManager方法
JDBC连接数据库 •创建一个以JDBC连接数据库的程序,包括7个步骤: 1.载入JDBC驱动程序: 在连接数据库之前.首先要载入想要连接的数据库的驱动到JVM(Java虚拟机). 这通过java.l ...
- js 日期 (10 + '').length == 10 ? '0' + 10 : 10;
js 日期 (10 + '').length == 10 ? '0' + 10 : 10;
- Appium基于安卓的各种FindElement的控件定位
转自:http://www.2cto.com/kf/201410/340345.html 1. findElementByName 1.1 示例 ? 1 2 el = driver.findEleme ...