AC日记——【模板】树链剖分 洛谷 P3384
题目描述
如题,已知一棵包含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取模)
输入输出样例
- 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
- 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的更多相关文章
- [luogu P3384] [模板]树链剖分
[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...
- luoguP3384 [模板]树链剖分
luogu P3384 [模板]树链剖分 题目 #include<iostream> #include<cstdlib> #include<cstdio> #inc ...
- [洛谷P3384] [模板] 树链剖分
题目传送门 显然是一道模板题. 然而索引出现了错误,狂wa不止. 感谢神犇Dr_J指正.%%%orz. 建线段树的时候,第44行. 把sum[p]=bv[pos[l]]%mod;打成了sum[p]=b ...
- 模板 树链剖分BFS版本
//点和线段树都从1开始 //边使用vector vector<int> G[maxn]; ],num[maxn],iii[maxn],b[maxn],a[maxn],top[maxn], ...
- AC日记——红色的幻想乡 洛谷 P3801
红色的幻想乡 思路: 线段树+容斥原理: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #de ...
- AC日记——无线网络发射器选址 洛谷 P2038
题目描述 随着智能手机的日益普及,人们对无线网的需求日益增大.某城市决定对城市内的公共场所覆盖无线网. 假设该城市的布局为由严格平行的129 条东西向街道和129 条南北向街道所形成的网格状,并且相邻 ...
- AC日记——小A的糖果 洛谷七月月赛
小A的糖果 思路: for循环贪心: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #defi ...
- AC日记——矩阵取数游戏 洛谷 P1005
矩阵取数游戏 思路: dp+高精: 代码: #include <bits/stdc++.h> using namespace std; #define ll long long struc ...
- AC日记——妖梦拼木棒 洛谷 P3799
妖梦拼木棒 思路: 神特么题: 代码: #include <bits/stdc++.h> using namespace std; #define mod 1000000007LL int ...
随机推荐
- 使用JFreeChart生成报表
1.JFreeChart简介 JFreeChart是JAVA平台上的一个开放的图表绘制类库.它完全使用JAVA语言编写,是为applications,servlets以及JSP等使用所设计. ...
- HDU 6156 回文 数位DP(2017CCPC)
Palindrome Function Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 256000/256000 K (Java/Ot ...
- WebView的初体验
使用安卓自带控件可以实现不通过浏览器即可上网的功能 突然就觉得安卓好强大,是不是我太无知了,太容易满足了 1.在layout中添加VebView控件 2.在Activity中设置WebView的属性 ...
- 10,Scrapy简单入门及实例讲解
Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以 ...
- 1 django
1.MVC 大部分开发语言中都有MVC框架 MVC框架的核心思想是:解耦 降低各功能模块之间的耦合性,方便变更,更容易重构代码,最大程度上实现代码的重用 m表示model,主要用于对数据库层的封装 v ...
- 4 Template层 -定义模板
1.模板介绍 作为Web框架,Django提供了模板,可以很便利的动态生成HTML 模版系统致力于表达外观,而不是程序逻辑 模板的设计实现了业务逻辑(view)与显示内容(template)的分离,一 ...
- P1616 疯狂的采药
P1616 疯狂的采药 题目背景 此题为NOIP2005普及组第三题的疯狂版. 此题为纪念LiYuxiang而生. 题目描述 LiYuxiang是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为 ...
- jq相关细节-1
animate/动画 所有用于动画的属性必须是数字的,除非另有说明:这些属性如果不是数字的将不能使用基本的jQuery功能.(例如,width, height或者left可以执行动画,但是backgr ...
- 1、IOS学习计划
2015年12月10日 -- 2015年12月27日(一共3个周末,12个个工作日) 1.斯坦福公开课(IOS7应用开发) 一共18节课程,通过视频和demo建立感觉 2.千峰的OC课程 一共25节课 ...
- 【BZOJ 3620】似乎在梦中见过的样子
题目 (夢の中で逢った.ような--) 「Madoka,不要相信 QB!」伴随着 Homura 的失望地喊叫,Madoka 与 QB 签订了契约. 这是 Modoka 的一个噩梦,也同时是上个轮回中所发 ...