[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],那么需要要 ...
随机推荐
- libusb 示例
#include <usb.h> #include <stdio.h> #define VERSION "0.1.0" #define VENDOR_ID ...
- mysql————表类型(存储引擎)的选择
表类型(存储引擎)的选择 7.1 mysql存储引擎概述 插件式存储引擎是mysql数据库最重要的特性之一,用户可以根据应用的需要选择ruhr存储和索引数据,是否使用事务等. InnoDB和BDB提供 ...
- DOM遍历查找结点
一.遍历API(2个) 1.深度优先原则遍历NodeIterator 节点迭代器 创建遍历API对象: var iterator=document.createNodeIterator(开始的父节点对 ...
- bzoj4430 [Nwerc2015]Guessing Camels赌骆驼
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4430 [题解] 把每只骆驼在第一个人.第二个人.第三个人的位置找出来,然后做三维偏序即可. ...
- 之江学院第0届校赛 qwb去面试 (找规律)
Description 某一天,qwb去WCfun面试,面试官问了他一个问题:把一个正整数n拆分成若干个正整数的和,请求出这些数乘积的最大值. qwb比较猥琐,借故上厕所偷偷上网求助,聪明的你能帮助他 ...
- hdu 2817 A sequence of numbers(快速幂取余)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2817 题目大意:给出三个数,来判断是等差还是等比数列,再输入一个n,来计算第n个数的值. #inclu ...
- Django-内置Admin
Django内置的Admin是对于model中对应的数据表进行增删改查提供的组件,使用方式有: 依赖APP: django.contrib.auth django.contrib.contenttyp ...
- linux进程的休眠(等待队列)【转】
转自:http://www.cnblogs.com/noaming1900/archive/2011/01/14/1935526.html (转载) bojan 收录于2010-10-09 阅读数: ...
- 简单粗暴的webapp语言国际化
不同语言以json格式存放不同文件 { "information": "个人资料", "fuckworld":"你好世界" ...
- [ Python - 15 ] win7安装paramiko问题总汇
安装环境: win7 sp1 python3.5 安装paramiko 新装的win7 sp1 x64位系统,安装好python3.5和pycharm后,需要用到paramiko模块于是开始安装: & ...