EOJ Monthly 2021.1 Sponsored by TuSimple
C. 魔树
题意:
第 0年,Cuber QQ 种下了一棵魔树。这是一棵有 n个结点的有根树,它的根为 1 号结点。
接下来 m 年,每年 Cuber QQ 都会施展魔法来改变这棵树。有两种魔法:
A k:对于树中的每个叶子,让它长出 k 个并排的孩子;
D: 对于树中的所有叶子,将它们删除。
有根树的叶子是指没有孩子的点。注意对于操作完的树,它的叶子集合可能会改变。
现在你知道了 Cuber QQ 每年施展的魔法。你想要预测 m 年以后,魔树会包含多少个点。你只需要求出答案对1e9 + 7 取模的结果。
保证 Cuber QQ 不会在根结点为叶子时使用第二种魔法。
输入格式
第一行两个整数 n,m(1<=n,m<=1e5)。
接下来 n - 1 行,每行两个整数 u,v(1 <= u,v <= n,u≠v),表示第 0年魔树中的一条边。
接下来 m行,第 i 行一个形如 A k(1 <= k <= 1e+7)或 D 的字符串,表示 Cuber QQ 第i 年进行的操作。
输出格式
一行一个整数,表示答案。
样例
input
5 3
1 2
2 3
2 4
4 5
A 1
D
A 2
output
9
input
1 10
A 2
D
A 3
A 4
D
A 5
A 6
A 7
D
A 8
output
829
提示
对于样例一,第 1年加入的点在第 2年全被删除,第 3年加入了 4 个点,故最终有 9个点。
思路:
首先我们用一个栈维护增删操作.
如果操作是’A’,就加入栈
如果是D,栈空 cnt++(cnt记录一共要先删除几层)
栈不为空,弹出栈顶.
其次我们怎么删除呢???
我们先记录最开始的那棵树每个点距离叶子结点的最远距离(因为可能不止一个叶子,需要比较,取最大值),把距离小于cnt的删掉就可以
怎么增加呢???
假设我第一次k = 3
第二次k = 4
那么就增加了3 * 4 = 12 个结点,以此类推乘法
代码实现:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
const ll mod = 1e9 + 7;
vector<int>G[maxn];
stack<char> st;
stack<int> s;
int dep[maxn];
int vis[maxn];
int dfs(int now){
int len = G[now].size();
if(len == 0){
dep[now] = 0;
}
for(int i = 0;i < len;i++){
int cur = G[now][i];
if(!vis[cur]){
vis[cur] = 1;
dep[now] = max(dfs(cur) + 1,dep[now]);
}
}
return dep[now];
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
int u,v;
for(int i = 1;i < n;i++){
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
memset(dep,0,sizeof(dep));
memset(vis,0,sizeof(vis));
vis[1] = 1;
dep[1] = dfs(1);
char x;
int y;
getchar();
int f = 0;
for(int i = 1;i <= m;i++){
scanf("%c",&x);
getchar();
if(x == 'A'){
scanf("%d",&y);
getchar();
st.push(x);
s.push(y);
}
else{
if(!st.empty()){
st.pop();
s.pop();
}
else{
f++;
}
}
}
int pre[maxn];
memset(pre,0,sizeof(pre));
int tot = 0;
while(!s.empty()){
pre[++tot] = s.top();
s.pop();
}
ll ans = 0;
ll res = 0;
for(int i = 1;i <= n;i++){
//假设f = 0,不会删除任何结点。
if(dep[i] > f){
ans++;
}
if(dep[i] == f){
res++;
}
}
//先加再取模和先取模再加得到的结果是不一定相同的。
for(int i = tot;i >= 1;i--){
ans = (ans + res) % mod;
res = (res * pre[i]) % mod;
}
ans = (ans + res) % mod;
printf("%lld\n",ans);
return 0;
}