[CF607D]Power Tree
题目大意:
一棵树初始只有一个编号为$1$的权值为$w_1$的根。$q(q\le2\times10^5)$次操作,每次可以给出$v,w(w<10^9)$,新建一个结点作为$v$的子结点,权值为$w$;或者给出$u$,求出$f(u)$。定义$f(u)=|S|\cdot\sum_{d\in S}d$,其中$S$为$w_u$与其所有子结点$v$的$f(v)$构成的可重集合。
思路:
首先将树全部建好,用线段树维护DFS序。每次新加结点相当于将这一结点的权值由$0$变为$w$,用线段树计算加上这个点以后的贡献。题目就变成了线段树上单点加、区间乘、区间求和问题。时间复杂度$O(q(\log n+\log w))$,其中$O(\log w)$是求逆元的复杂度。
#include<cstdio>
#include<cctype>
#include<forward_list>
using int64=long long;
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
constexpr int N=2e5+,Q=2e5,mod=1e9+;
int w[N],n,dfn[N],par[N],size[N],s[N];
std::forward_list<int> e[N];
inline void add_edge(const int &u,const int &v) {
e[u].push_front(v);
}
struct Operation {
int type,v,u;
};
Operation o[N];
void exgcd(const int &a,const int &b,int &x,int &y) {
if(!b) {
x=,y=;
return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
int inv(const int &x) {
int ret,tmp;
exgcd(x,mod,ret,tmp);
return (ret%mod+mod)%mod;
}
void dfs(const int &x) {
size[x]=;
dfn[x]=++dfn[];
for(auto &y:e[x]) {
dfs(y);
size[x]+=size[y];
}
}
class SegmentTree {
#define _left <<1
#define _right <<1|1
private:
int val[N<<],tag[N<<];
void push_up(const int &p) {
val[p]=(val[p _left]+val[p _right])%mod;
}
void push_down(const int &p) {
if(tag[p]==) return;
tag[p _left]=(int64)tag[p _left]*tag[p]%mod;
tag[p _right]=(int64)tag[p _right]*tag[p]%mod;
val[p _left]=(int64)val[p _left]*tag[p]%mod;
val[p _right]=(int64)val[p _right]*tag[p]%mod;
tag[p]=;
}
public:
void build(const int &p,const int &b,const int &e) {
tag[p]=;
if(b==e) return;
const int mid=(b+e)>>;
build(p _left,b,mid);
build(p _right,mid+,e);
}
void add(const int &p,const int &b,const int &e,const int &x,const int &v) {
(val[p]+=v)%=mod;
if(b==e) return;
push_down(p);
const int mid=(b+e)>>;
if(x<=mid) add(p _left,b,mid,x,v);
if(x>mid) add(p _right,mid+,e,x,v);
}
void mul(const int &p,const int &b,const int &e,const int &l,const int &r,const int &v) {
if(b==l&&e==r) {
val[p]=(int64)val[p]*v%mod;
tag[p]=(int64)tag[p]*v%mod;
return;
}
push_down(p);
const int mid=(b+e)>>;
if(l<=mid) mul(p _left,b,mid,l,std::min(mid,r),v);
if(r>mid) mul(p _right,mid+,e,std::max(mid+,l),r,v);
push_up(p);
}
int query(const int &p,const int &b,const int &e,const int &l,const int &r) {
if(b==l&&e==r) {
return val[p];
}
push_down(p);
int ret=;
const int mid=(b+e)>>;
if(l<=mid) (ret+=query(p _left,b,mid,l,std::min(mid,r)))%=mod;
if(r>mid) (ret+=query(p _right,mid+,e,std::max(mid+,l),r))%=mod;
return ret;
}
#undef _left
#undef _right
};
SegmentTree t;
int main() {
w[n=]=getint();
const int q=getint();
for(register int i=;i<q;i++) {
o[i].type=getint();
if(o[i].type==) {
o[i].v=par[++n]=getint();
add_edge(par[n],n);
w[o[i].u=n]=getint();
}
if(o[i].type==) {
o[i].v=getint();
}
}
dfs();
s[]=;
t.build(,,n);
t.add(,,n,,w[]);
for(register int i=;i<q;i++) {
const int &y=o[i].u,&x=o[i].v;
if(o[i].type==) {
t.add(,,n,dfn[y],(int64)t.query(,,n,dfn[x],dfn[x])*inv(w[x])%mod*w[y]%mod);
t.mul(,,n,dfn[x],dfn[x]+size[x]-,(int64)inv(s[x])*(s[x]+)%mod);
s[x]+=s[y]=;
}
if(o[i].type==) {
const int ans=t.query(,,n,dfn[x],dfn[x]+size[x]-);
if(x==) {
printf("%d\n",ans);
continue;
}
printf("%d\n",int((int64)ans*w[par[x]]%mod*inv(t.query(,,n,dfn[par[x]],dfn[par[x]]))%mod));
}
}
return ;
}
[CF607D]Power Tree的更多相关文章
- CF1120D Power Tree
沙发~~ 题意简述 给你一棵有根树,定义叶子为度数为1的点. 你可以以$ w_x \(的代价控制\)x\(点.选择控制之后可以给它的子树里的叶子加 上\)t (t \in Z )$. 你要以最小的总代 ...
- Codeforces 1120D Power Tree [最小生成树]
洛谷 Codeforces 这题怎么一个中文题解都没有,是不是你们都认为太水了-- 思路 显然可以用dfs序把每个节点变成给一个区间的叶子节点加上某个数. 显然把叶子序列差分一下变为\(a_1,a_2 ...
- CF1120D Power Tree(构造题,差分,最小生成树)
很有趣的一道题. 首先可以对每个叶子进行编号.按照DFS到的顺序即可.(假设从 $1$ 到 $k$) 然后对每个点求出它管辖的所有叶子的编号.因为是DFS序所以这一定是个区间.设点 $u$ 的这个区间 ...
- cf Round 607
A.Chain Reaction(DP+二分) 题意:一排有n个灯塔,每个灯塔给出坐标xi和力量yi,每次从最右边依次点亮灯塔,每点亮一个灯塔,它左边的距离它yi范围内的灯塔将受到损坏.现在允许在最右 ...
- codeforces选做
收录了最近本人完成的一部分codeforces习题,不定期更新 codeforces 1132E Knapsack 注意到如果只使用某一种物品,那么这八种物品可以达到的最小相同重量为\(840\) 故 ...
- Codeforces Round #543 Div1题解(并不全)
Codeforces Round #543 Div1题解 Codeforces A. Diana and Liana 给定一个长度为\(m\)的序列,你可以从中删去不超过\(m-n*k\)个元素,剩下 ...
- Codeforces Round #539Ȟȟȡ (Div. 1) 简要题解
Codeforces Round #539 (Div. 1) A. Sasha and a Bit of Relax description 给一个序列\(a_i\),求有多少长度为偶数的区间\([l ...
- ZOJ 3684 Destroy 树的中心
中心节点就是树的中心,2遍dfs求到树的直径.而中心一定在直径上,顺着直径找到中心就够了. 然后能够一遍树形DP找到最小值或者二分+推断是否訪问到叶子节点. #include <iostream ...
- Codeforces Round #543 (Div. 1, based on Technocup 2019 Final Round) 题解
题面戳这里 A. Diana and Liana 首先如果s>ks>ks>k一定无解,特判一下.那么我们考虑找恰好满足满足题目中的要求的区间[l,r][l,r][l,r],那么需要要 ...
随机推荐
- vue入门知识
vue的特点在于:响应的数据绑定.组合的视图组件. vue的文件,分成三个部分<template>html模板</template> <script>js< ...
- Java输入输出流备忘
重要博客: http://blog.csdn.net/hguisu/article/details/7418161 File dir = new File("\\root"); ...
- POJ 3070 + 51Nod 1242 大斐波那契数取余
POJ 3070 #include "iostream" #include "cstdio" using namespace std; class matrix ...
- Things To Do Before NOI2017
TC div1 10套 数据结构 25题 网络流 10题 字符串 20题 数学 15题 图论 15题 计算几何 5题 提交答案 5题 嗯...先这些吧... 以上所有题目,博客都会有更新--- NOI ...
- ACM-ICPC 2018 南京赛区网络预赛 Sum
A square-free integer is an integer which is indivisible by any square number except 11. For example ...
- 【转载】字符串最小表示法-O(n)算法
原博客链接:http://blog.csdn.net/zy691357966/article/details/39854359 未授权,侵权删. 因为这篇博客写得真好..转载了.. 红色的字是原博主写 ...
- 用java实现word转html
由于项目需要,要完成将上传的word文件转成html文件的功能.在网上搜了一下,大致有3种方法:1.用jacob实现 2.用poi实现 3.用openoffice实现. 从网上来看好像jacob用的人 ...
- Chrome扩展及应用开发
Chrome扩展及应用开发(电子书) http://www.ituring.com.cn/minibook/950 文档 官方 https://developer.chrome.com/extensi ...
- mybatis插入值的时候返回对象的主键值
mapping文件: <insert id="insert" parameterType="com.vimtech.bms.business.riskproject ...
- centos 7 卸载自带的jdk
# 查看jdk安装信息 rpm -qa|grep java 卸载已安装的jdk: # yum -y remove java java-1.7.0-*