昨天的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;
}
?