昨天的CF自己太挫了。一上来看到A题,就有思路,然后马上敲,但是苦于自己很久没有敲计数的题了,许多函数都稍微回忆了一阵子。A题的主要做法就是将每个数质因数分解,统计每个质因子的个数,对于每个质因子pi的个数k,等价于解一个方程x1+x2+...+xn=k的有多少个非负整数解,学过离散数学或者一些组合数学的就会知道,答案是C(k,n+k-1),但是由于n+k-1可能会很大,我一开始考虑小了,贡献了好多次RE,所以在算组合数的时候只能算出每个数的阶乘以及对应的逆元去算,然后将每个因子算出来的结果乘起来就可以了。

B的话写一下就会发现很明显的能够裂项,所以问题就转换成求u(n),v(n),n的大小达到10^9,但是基于素数的稠密性我们可以在有限的时间内算出来,10^11以内的相邻素数间隔貌似是在400多还是500多,每次判素数的复杂度是根号n,所以大致找出u(n),v(n)的时间是在10^7以内,这个在CF上绝对是可以算的,知道u,v后面的就是简单的计算一下。当然为了加快速度,可以考虑素性测试。

C的话拿到的时候时间不多了,想了一下就有了思路,但是10分钟真的打不出来,于是就想想算了。今天才打出来的。在树上对结点以及它的后代进行更新自然是先把这棵树搜成dfs序列,但是像题目这种,隔一层-k的怎么办呢? 可以考虑建两棵线段树,首先预处理出每棵树的深度dep,每次更新的时候就在第一棵线段树上每个结点加上x+k*dep[v],然后再在第二棵线段树上加上-k。 那么询问的时候怎么办呢? 询问的时候的答案就是 该结点在第一棵线段树上的值ans1,加上在第二棵线段树上的值ans2乘上对应结点的深度 即 ans1+ans2*dep[v]。可以优化的地方是其实并不需要建两棵,只是一棵线段数维护两个值而已,我写的这份代码很慢,1.9s,差不多都超时了,不过也没有办法啦。

#pragma warning(disable:4996)
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<cmath>
#include<map>
#define maxn 300500
#define ll long long
#define mod 1000000007
using namespace std; struct Node
{
int l, r;
ll add, sum;
}; struct SegmentTree
{
Node N[4 * maxn];
void build(int i, int L, int R)
{
N[i].l = L; N[i].r = R; N[i].sum = N[i].add = 0;
if (L == R){
return;
}
int M = (L + R) >> 1;
build(i << 1, L, M);
build(i << 1 | 1, M + 1, R);
} void pushDown(int i)
{
ll tt = N[i].add;
if (N[i].l == N[i].r) return;
if (tt != 0){
(N[i << 1].add += tt) %= mod;
(N[i << 1 | 1].add += tt) %= mod;
(N[i << 1].sum += (N[i << 1].r - N[i << 1].l + 1)*tt%mod) %= mod;
(N[i << 1 | 1].sum += (N[i << 1 | 1].r - N[i << 1 | 1].l + 1)*tt%mod) %= mod;
N[i].add = 0;
}
} void pushUp(int i)
{
N[i].sum = (N[i << 1].sum + N[i << 1 | 1].sum) % mod;
} void add(int i, int L, int R, ll s)
{
if (N[i].l == L&&N[i].r == R){
(N[i].add += s) %= mod;
(N[i].sum += (R - L + 1)*s) %= mod;
return;
}
pushDown(i);
int M = (N[i].l + N[i].r) >> 1;
if (R <= M) add(i << 1, L, R, s);
else if (L > M) add(i << 1 | 1, L, R, s);
else add(i << 1, L, M, s), add(i << 1 | 1, M + 1, R, s);
pushUp(i);
}
ll query(int i, int L, int R)
{
if (N[i].l == L&&N[i].r == R){
return N[i].sum;
}
pushDown(i);
int M = (N[i].l + N[i].r) >> 1;
if (R <= M) return query(i << 1, L, R);
else if (L > M) return query(i << 1 | 1, L, R);
else return query(i << 1, L, M) + query(i << 1 | 1, M + 1, R);
//pushUp(i);
}
}st[2]; int n;
vector<int> G[maxn];
int dep[maxn];
int pre[maxn];
int post[maxn];
int dfs_clock; void dfs(int u, int fa,int d)
{
pre[u] = ++dfs_clock;
dep[u] = d;
for (int i = 0; i < G[u].size(); i++){
int v = G[u][i];
if (v == fa) continue;
dfs(v, u, d + 1);
}
post[u] = dfs_clock;
} int main()
{
while (cin >> n)
{
for (int i = 0; i <= n; i++) G[i].clear();
int vi;
for (int i = 2; i <= n; i++){
scanf("%d", &vi);
G[vi].push_back(i);
G[i].push_back(vi);
}
dfs_clock = 0;
dfs(1, -1, 0);
st[0].build(1, 1, n); st[1].build(1, 1, n);
int q; scanf("%d", &q);
ll vq, xq, kq;
int tq;
for (int i = 0; i < q; i++){
scanf("%d", &tq);
if (tq == 1){
scanf("%I64d%I64d%I64d", &vq, &xq, &kq);
st[0].add(1, pre[vq], post[vq], (xq + dep[vq] * kq)%mod);
st[1].add(1, pre[vq], post[vq], -kq);
}
else{
ll ans = 0; scanf("%d", &vq);
ans = (ans + st[0].query(1, pre[vq], pre[vq])) % mod;
ans = (ans + st[1].query(1, pre[vq], pre[vq])*dep[vq]) % mod;
ans = (ans + mod) % mod;
printf("%I64d\n", ans);
}
}
}
return 0;
}

CodeForces369C On Changing Tree的更多相关文章

  1. CF396C On Changing Tree

    CF396C On Changing Tree 给定一棵以 \(1\) 为根的树,初始时所有点权为 \(0\) 有 \(m\) 次操作,分为两种 \(1\ u\ x\ k\) 表示给以 \(u\) 的 ...

  2. CodeForces 396C On Changing Tree

    On Changing Tree Time Limit: 2000ms Memory Limit: 262144KB This problem will be judged on CodeForces ...

  3. CodeForces - 396C On Changing Tree(树状数组)

    题目大意 给定一棵以1为根的树,初始时所有点为0 给出树的方式是从节点2开始给出每一个点的父亲 然后是 $m$ 次操作,分为两种 $1 v,k,x$ 表示在以v为根的子树中的每一个点上添加 $x-i* ...

  4. CDQ分治题目小结

    CDQ分治属于比较特殊的一类分治,许多问题转化为这类分治的时候,时空方面都会有很大节省,而且写起来没有这么麻烦. 这类分治的特殊性在于分治的左右两部分的合并,作用两部分在合并的时候作用是不同的,比如, ...

  5. Codeforces Round #232 (Div. 1)

    这次运气比较好,做出两题.本来是冲着第3题可以cdq分治做的,却没想出来,明天再想好了. A. On Number of Decompositions into Multipliers 题意:n个数a ...

  6. ASP.NET 生命周期(原文翻译)

    在网上看到这篇文章,老外写的,里面很多图片挺精致,顺带翻译过来给大家分享下,英语太次好多地方都翻不过来 ASP.NET application and page life cycle Download ...

  7. CQD(陈丹琦)分治 & 整体二分——专题小结

    整体二分和CDQ分治 有一些问题很多时间都坑在斜率和凸壳上了么--感觉斜率和凸壳各种搞不懂-- 整体二分 整体二分的资料好像不是很多,我在网上找到了一篇不错的资料:       整体二分是个很神的东西 ...

  8. web forms page和control的生命周期life cycle交互,以及page生命周期中每个event中需要做什么事情

    只有 page_load和page_init这些可以autoeventwireup RenderControl只提供override public override void RenderContro ...

  9. codeforces396C

    On Changing Tree CodeForces - 396C You are given a rooted tree consisting of n vertices numbered fro ...

随机推荐

  1. Java序列化与反序列化(Serializable)

    Java序列化与反序列化(Serializable) 特别注意: 1.要序列化的类必须实现Serializable借口 2.在反序列化(读取对象)的时候必须额外捕获EOFException 3.序列化 ...

  2. DB2&&oracle-培训内容

    DB2 1 Data Sharing架构,高可用 2 DB2的对象主要有以下几类:database,storage group, Tablspace, indexspace, table,index ...

  3. Populating Next Right Pointers in Each Node II

    题目地址: https://oj.leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/ 关键思路:讲节点的左右子节 ...

  4. 第四届蓝桥杯C/C++A组题目:振兴中华

    首先把题目贴上来吧! 小明参加了学校的趣味运动会,其中的一个项目是:跳格子. 地上画着一些格子,每个格子里写一个字,如下所示:(也可参见图1) 从我做起振 我做起振兴 做起振兴中 起振兴中华 图1 比 ...

  5. Linux进程间通信方法总结

    ①匿名管道(pipe) 匿名管道(pipe)管道是一种半双工的通信方式,数据只能单向流动.如果要进行双工通信,需要建立两个管道.管道只能在具有亲缘关系的进程间使用,例如父子进程或兄弟进程. ②有名管道 ...

  6. Java抽象类和抽象方法例子

    题目:定义Shape类表示一般二维图形.Shape具有抽象方法area和perimeter,分别计算形状的面积和周长.试定义一些二维形状类(如矩形.三角形.圆形等),这些均为Shape类的子类并计算出 ...

  7. 验证中文、英文、电话、手机、邮箱、数字、数字和字母、Url地址和Ip地址的正则表达式

    Helper类代码 public class Helper { #region 单列循环 private Helper() { } private static Helper instance = n ...

  8. php中url传递中文字符,特殊危险字符的解决方法

    php中的urldecode,base64_encode函数然后再结合自己写的替换函数来进行安全传递url中文字符,特殊危险字符. 需要在url中传递中文字符或是其它的html等特殊字符,似乎总会有各 ...

  9. perl中shift 和unshift 操作

    ##################################################################### unshift 和shift 对一个数组的开头进行操作(数组 ...

  10. mapreduce 实现矩阵乘法

    import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs ...