题目大意:
  一棵树初始只有一个编号为$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的更多相关文章

  1. CF1120D Power Tree

    沙发~~ 题意简述 给你一棵有根树,定义叶子为度数为1的点. 你可以以$ w_x \(的代价控制\)x\(点.选择控制之后可以给它的子树里的叶子加 上\)t (t \in Z )$. 你要以最小的总代 ...

  2. Codeforces 1120D Power Tree [最小生成树]

    洛谷 Codeforces 这题怎么一个中文题解都没有,是不是你们都认为太水了-- 思路 显然可以用dfs序把每个节点变成给一个区间的叶子节点加上某个数. 显然把叶子序列差分一下变为\(a_1,a_2 ...

  3. CF1120D Power Tree(构造题,差分,最小生成树)

    很有趣的一道题. 首先可以对每个叶子进行编号.按照DFS到的顺序即可.(假设从 $1$ 到 $k$) 然后对每个点求出它管辖的所有叶子的编号.因为是DFS序所以这一定是个区间.设点 $u$ 的这个区间 ...

  4. cf Round 607

    A.Chain Reaction(DP+二分) 题意:一排有n个灯塔,每个灯塔给出坐标xi和力量yi,每次从最右边依次点亮灯塔,每点亮一个灯塔,它左边的距离它yi范围内的灯塔将受到损坏.现在允许在最右 ...

  5. codeforces选做

    收录了最近本人完成的一部分codeforces习题,不定期更新 codeforces 1132E Knapsack 注意到如果只使用某一种物品,那么这八种物品可以达到的最小相同重量为\(840\) 故 ...

  6. Codeforces Round #543 Div1题解(并不全)

    Codeforces Round #543 Div1题解 Codeforces A. Diana and Liana 给定一个长度为\(m\)的序列,你可以从中删去不超过\(m-n*k\)个元素,剩下 ...

  7. Codeforces Round #539&#542&#543&#545 (Div. 1) 简要题解

    Codeforces Round #539 (Div. 1) A. Sasha and a Bit of Relax description 给一个序列\(a_i\),求有多少长度为偶数的区间\([l ...

  8. ZOJ 3684 Destroy 树的中心

    中心节点就是树的中心,2遍dfs求到树的直径.而中心一定在直径上,顺着直径找到中心就够了. 然后能够一遍树形DP找到最小值或者二分+推断是否訪问到叶子节点. #include <iostream ...

  9. 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],那么需要要 ...

随机推荐

  1. sql异常-The used SELECT statements have a different number of columns

    两个或多个select查询进行union时,查询的列不对应.两个select进行union时,两个select的查询出的列必须相对应.

  2. Installing Jenkins to Centos Docker

    1.Install Docker CE to Centos7 [root@zoo1 ~]# yum install -y yum-utils device-mapper-persistent-data ...

  3. Nginx中的长连接

    在nginx中,对于http1.0与http1.1是支持长连接的 我们知道,http请求是基于TCP协议之上的,那么,当客户端在发起请求前,需要先与服务端建立TCP连接,而每一次的TCP连接是需要三次 ...

  4. python并发进程

    1 引言 2 创建进程 2.1 通过定义函数的方式创建进程 2.2 通过定义类的方式创建进程 3 Process中常用属性和方法 3.1 守护进程:daemon 3.2 进程终结于存活检查:termi ...

  5. 【poj3420】递推式转矩阵乘法

    历史性的时刻!!! 推了一晚上!和hyc一起萌萌哒地推出来了!! 被摧残蹂躏的智商啊!!! 然而炒鸡高兴!! (请不要介意蒟蒻的内心独白..) 设a[i]为扫到第i行时的方案数. 易知,对于一行1*4 ...

  6. 【BZOJ 3907】网格(Catalan数)

    题目链接 这个题推导公式跟\(Catalan\)数是一样的,可得解为\(C_{n+m}^n-C_{n+m}^{n+1}\) 然后套组合数公式\(C_n^m=\frac{n!}{m!(n-m)!}\) ...

  7. NYOJ 38 布线问题 (最小生成树 prim)

    题目链接 描述 南阳理工学院要进行用电线路改造,现在校长要求设计师设计出一种布线方式,该布线方式需要满足以下条件: 1.把所有的楼都供上电. 2.所用电线花费最少 输入 第一行是一个整数n表示有n组测 ...

  8. js判断浏览器是否为ie

    使用传统方式 if ((navigator.userAgent.indexOf('MSIE') >= 0) && (navigator.userAgent.indexOf('Op ...

  9. MySQL中EXISTS的用法

    比如在Northwind数据库中有一个查询为 SELECT c.CustomerId,CompanyName FROM Customers c WHERE EXISTS( SELECT OrderID ...

  10. HDU1010(dfs+剪枝)

    Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...