青出于蓝胜于蓝(jisuanke)
武当派一共有 nn 人,门派内 nn 人按照武功高低进行排名,武功最高的人排名第 11,次高的人排名第 22,... 武功最低的人排名第 nn。现在我们用武功的排名来给每个人标号,除了祖师爷,每个人都有一个师父,每个人可能有多个徒弟。
我们知道,武当派人才辈出,连祖师爷的武功都只能排行到 pp。也就是说徒弟的武功是可能超过师父的,所谓的青出于蓝胜于蓝。
请你帮忙计算每个人的所有子弟(包括徒弟的徒弟,徒弟的徒弟的徒弟....)中,有多少人的武功超过了他自己。
输入格式
输入第一行两个整数 n, p(1 le n le 100000, 1 le p le n)n,p(1≤n≤100000,1≤p≤n)。
接下来 n-1n−1 行,每行输入两个整数 u, v(1 le u, v le n)u,v(1≤u,v≤n),表示 uu 和 vv 之间存在师徒关系。
输出格式
输出一行 nn 个整数,第 ii 个整数表示武功排行为 ii 的人的子弟有多少人超过了他。
行末不要输出多余的空格。
样例输入
10 5 5 3 5 8 3 4 3 1 2 1 6 7 8 7 9 8 8 10
样例输出
0 0 2 0 4 0 1 2 0 0
其实就是查询区间(l,r]有几个。由于是从名次第一开始,所以往后的名次只要在dfs序中有值便是名次比自己高但是是自己的徒弟,如果不在同一子树上,会因为dfs序的r[i]所分开,到最后只是算dfs在(l,r]这个区间的值
#include<stdio.h> #include<vector> using namespace std; const int N=1e5+5,MD=1e9+7; int L[N],R[N],c[N]; int tot,n; vector<int>G[N]; void dfs(int u,int fa)//处理出dfs序 { L[u]=++tot; for(auto X:G[u])if(X!=fa)dfs(X,u); R[u]=tot; } void add(int x,int val) { for(int i=x; i<=n; i+=(i&-i)) c[i]+=val; } int Sum(int x) { int ans=0; for(int i=x; i; i-=(i&-i)) ans+=c[i]; return ans; } int main() { int rt; scanf("%d%d",&n,&rt); for(int i=2,u,v; i<=n; i++) scanf("%d%d",&u,&v),G[u].push_back(v),G[v].push_back(u); tot=0; dfs(rt,-1); for(int i=1;i<n;i++)printf("%d ",Sum(R[i])-Sum(L[i])),add(L[i],1); printf("%d",Sum(R[n])-Sum(L[n])); }
链接:https://www.nowcoder.com/acm/contest/91/B
来源:牛客网
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
输入描述:
输入测试组数T,每组数据,输入n+1行整数,第一行为n和p,1<=n<=20000, 1<=p<=n, 接下来n-1行,每行两个整数u和v,表示u和v之间有一条边。第n+1行输入n个整数val1, val2,…, valn,其中1<=vali<=10000,1<=i<=n.
输出描述:
对于每组数据,输出一行,包含1个整数, 表示对1000000007取模后的结果
输入
2 5 4 5 3 2 5 4 2 1 3 10 4 3 10 5 3 3 1 3 2 1 1 10 1
输出
11 2
备注:
n>=10000的有20组测试数据
先预处理合数的倍数,然后就是dfs序了
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll MD=1e9+7; vector<int> v[20020],d[10005]; int n,rt,vis[10005]; ll val[20020],ans,f[20020]; void dfs(int x,int pre) { for(auto X:d[val[x]])f[X]=(f[X]+x)%MD; ans=(ans+f[val[x]])%MD; for(auto X:v[x])if(X!=pre)dfs(X,x); for(auto X:d[val[x]])f[X]=(f[X]-x+MD)%MD; } int main() { for(int i=2; i<=10000; i++) if(!vis[i])for(int j=i+i; j<=10000; j+=i)vis[j]=1; for(int i=4; i<=10000; i++) if(vis[i])for(int j=i; j<=10000; j+=i)d[j].push_back(i); int T; cin>>T; while(T--) { ans=0; cin>>n>>rt; memset(vis,0,sizeof vis); for(int i=1; i<=n; i++)v[i].clear(); for(int i=1,x,y; i<n ; i++) cin>>x>>y,v[x].push_back(y),v[y].push_back(x); for(int i=1; i<=n; i++)cin>>val[i]; dfs(rt,-1); cout<<ans<<' '; } }
Change
There is a rooted tree with n nodes, number from 1-n. Root’s number is 1.Each node has a value ai.
Initially all the node’s value is 0.
We have q operations. There are two kinds of operations.
1 v x k : a[v]+=x , a[v’]+=x-k (v’ is child of v) , a[v’’]+=x-2*k (v’’ is child of v’) and so on.
2 v : Output a[v] mod 1000000007(10^9 + 7).
Input
First line contains an integer T (1 ≤ T ≤ 3), represents there are T test cases.
In each test case:
The first line contains a number n.
The second line contains n-1 number, p2,p3,…,pn . pi is the father of i.
The third line contains a number q.
Next q lines, each line contains an operation. (“1 v x k” or “2 v”)
1 ≤ n ≤ 3*10^5
1 ≤ pi < i
1 ≤ q ≤ 3*10^5
1 ≤ v ≤ n; 0 ≤ x < 10^9 + 7; 0 ≤ k < 10^9 + 7
Output
For each operation 2, outputs the answer.
Sample Input
1 3 1 1 3 1 1 2 1 2 1 2 2
Sample Output
2 1
这个题目的题意还是很简单的,就是一个访问x,就把它+x,他的孩子要多减去k,孙子多减2k
可以考虑用两个树状数组维护,一个维护x+deep[v]*k,一个-k
#include<stdio.h> #include<vector> using namespace std; const int N=3e5+5,MD=1e9+7; int L[N],R[N],deep[N],n; int a[N],b[N]; int tot; vector<int>G[N]; void dfs(int u)//处理出dfs序与每个点的深度 { L[u]=++tot; int l=G[u].size(); for(int i=0,v; i<l; i++) { v=G[u][i]; deep[v]=deep[u]+1; dfs(v); } R[u]=tot; } //差分思想 void adda(int x,int y)//维护x+deep[v]*k { for(int i=x; i<=n; i+=(i&-i)) a[i]=(a[i]+y)%MD; } void addb(int x,int y)//维护-k { for(int i=x; i<=n; i+=(i&-i)) b[i]=(b[i]+y)%MD; } int sum(int x,int y) { int ret=0,ans=0; for(int i=x; i; i-=(i&-i)) ret=(ret*1LL+a[i])%MD; for(int i=x; i; i-=(i&-i)) ans=(ans*1LL+b[i])%MD; ans=ans*1LL*(deep[y]+1)%MD; return (ret+ans)%MD; } int main() { int T,q; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=2,x; i<=n; i++)scanf("%d",&x),G[x].push_back(i); tot=0; dfs(1); scanf("%d",&q); for(int i=0,op,v,x,k; i<q; i++) { scanf("%d%d",&op,&v); if(op==1) { scanf("%d%d",&x,&k); int ret=(x+(deep[v]+1)*1LL*k)%MD; adda(L[v],ret); adda(R[v]+1,-ret+MD); addb(L[v],(-k+MD)%MD); addb(R[v]+1,k%MD); } else printf("%d ",sum(L[v],v)); } for(int i=1; i<=n; i++)G[i].clear(),a[i]=b[i]=deep[i]=0; } }