1 条题解
-
0
这是一道简单题。
题目中给定了这一张图的深搜顺序,那么我们就可以根据给定的顺序先建立出一颗 DFS 树。接下来,我们要在这个树上的某两个节点之间增加一条边,并且使得增加后对于最后结果的输出没有影响,记可以增加的边数为 ,则最终的答案为 。(因为既然每条边加上都没有影响,那么每条边都有加与不加两种选择,共 条边,答案即为 )。
考虑有哪些边是可加可不加的。对于某个点 ,如果有一个点 ,且 与 不是祖先与后代的关系,那么如果在 与 之间连接一条边,这条边一定会产生作用(遍历到最后一定会走),与定义相矛盾,又由于这是一条无向边,向上连和向下连本质上是对称的,那么就只要考虑向上连。再考虑编号所带来的限制,因为是按编号从小到大遍历的,所以如果要在 与 之间连一条边, 一定要严格大于 ,否则就会先走加入的边,与定义矛盾( 表示遍历到目前为止,点 的儿子的最大编号)。
最后可以得到结论:对于一个点 ,若其要与 连边,当且仅当 是 的祖先,且到目前为止, 编号最大的儿子的编号 要严格小于 。
这一部分可能有些难理解,建议读者自己动手画图感受一下,便于理解。
那么这是容易用树状数组去维护的,注意代码细节。
#include<bits/stdc++.h> #define int long long using namespace std; const int N=2e5+5,mod=1e9+7; int n,x,z,rt,cnt; char y; int dep[N],sum[N],id[N]; stack<int> st; vector<int> g[N]; int lowbit(int x){return x&(-x);} int ask(int x){ int res=0; while(x){ res+=sum[x]; x-=lowbit(x); } return res; } void add(int x,int v){ while(x<=n){ sum[x]+=v; x+=lowbit(x); } } void dfs(int u,int fa){ if(u>1) cnt+=ask(u-1); for(int i=0;i<g[u].size();i++){ if(g[u][i]==fa) continue; id[u]=max(id[u],g[u][i]); if(id[u]) add(id[u],1); dfs(g[u][i],u); if(id[u]) add(id[u],-1); } } int qpow(int c,int d){ int ans=1; while(d){ if(d&1) ans=(ans*c)%mod; c=c*c%mod; d>>=1; } return ans; } signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); while(cin>>x>>y>>z){ n++,z++; dep[z]=x; while(!st.empty() && dep[st.top()]>=dep[z]) st.pop(); if(!st.empty()){ int fa=st.top(); g[z].push_back(fa); g[fa].push_back(z); } st.push(z); } for(int i=1;i<=n;i++) sort(g[i].begin(),g[i].end()); dfs(n,0); cout<<qpow(2,cnt)<<'\n'; return 0; }
- 1
信息
- ID
- 12607
- 时间
- 1000ms
- 内存
- 300MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者