2084. Asm.Def的基本算法
Posted 小时のblog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2084. Asm.Def的基本算法相关的知识,希望对你有一定的参考价值。
【题目描述】
“有句美国俗语说,如果走起来像鸭子,叫起来像鸭子,那就是一只鸭子。”斯科特·华莱士看着Asm.Def面前屏幕上滚动的绿色字符,若有所思地说。
“什么意思?”
“你的数据。看上去是一棵树。”
“按照保密条令,我什么也不说这是最好的——但见你这么热情,一句话不说也不好。”Asm.Def停下手中的快速数论变换,“确实是树。”
“然后你怎么算出来目标的位置?”
“都需要按照基本算法,按照图论的那一套理论,去产生。听说过LCA吗?不是那个印度飞机,我是说最近公共祖先……”
Asm.Def通过分析无线电信号得到了一棵有n个节点,以1为根的树。除1之外,节点i的父亲是p_i。节点带有权值,节点i的权值是w_i。
我们定义某点的祖先为从根到它路径上的所有点(包括它本身),而两个节点a、b的最近公共祖先是某个点p,使得p同时是a、b的祖先,而且p离根最远。
Asm.Def想要求出
(文字:∑∑w_i*w_j*w_LCA(i,j)),
其中LCA(i,j)是i、j的最近公共祖先,他认为这个值至关重要。由于这个值可能很大,Asm.Def只需要知道它模1,000,000,007(即10^9+7)的结果。
【输入格式】
第1行两个整数:n和w_1.
第2行到第n行,第i行有两个整数p_i和w_i。
【输出格式】
一行一个整数,即答案模1,000,000,007的值。
【样例输入】
2 2 1 1
【样例输出】
17
【提示】
1×1×1+1×2×2+2×1×2+2×2×2=17。
对于30%的数据,n<=100,w_i<=10。
对于60%的数据,n<=1000,w_i<=1000.
对于100%的数据,1<=n<=10^5,0<=w_i<=10^9,1<=p_i<i.
【超时code】
dalao说没事先打暴力,说不定会想出思路,然而并没有。超时4个点。
用define定义的mod一直错 输出1e009...
然后建边时没有建双边....
树剖写错.....
#include<iostream> #include<cstdio> #include<vector> #include<algorithm> using namespace std; //#define mod 1e9 const int mod=1e9+7; int w[100008],dad[100008],size[100008],top[100008],deep[100008]; long long ans; int n,da; vector<int>vec[100008]; void dfs1(int x) { size[x]=1; deep[x]=deep[dad[x]]+1; for(int i=0; i<vec[x].size(); i++) { if(dad[x]!=vec[x][i]) { dad[vec[x][i]]=x; dfs1(vec[x][i]); size[x]+=size[vec[x][i]]; } } } void dfs2(int x) { if(!top[x])top[x]=x; int t=0; for(int i=0; i<vec[x].size(); i++) { if(dad[x]!=vec[x][i]&&size[vec[x][i]]>size[t]) t=vec[x][i]; } if(t) { // top[t]=x; top[t]=top[x]; dfs2(t); } for(int i=0; i<vec[x].size(); i++) { if(dad[x]!=vec[x][i]&&vec[x][i]!=t) dfs2(vec[x][i]); } } int lca(int x,int y) { for(; top[x]!=top[y];) { if(deep[x]<deep[y]) swap(x,y); // top[x]=dad[top[x]]; x=dad[top[x]]; } if(deep[x]<deep[y])return x; return y; } int main() { freopen("asm_algo.in","r",stdin); freopen("asm_algo.out","w",stdout); scanf("%d%d",&n,&w[1]); for(int i=2; i<=n; i++) { scanf("%d%d",&da,&w[i]); vec[da].push_back(i); vec[i].push_back(da);//建双向边 } dfs1(1); dfs2(1); for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) ans=(ans+w[i]*w[j]*w[lca(i,j)])%mod; cout<<ans<<endl; return 0; }
【AC code】
一气之下全改成long long 就过了。
【思路】
如图的矩阵表示i,j的lca。发现对角线两侧是对称的(因为i,j的lca==j,i的lca);
那么我们只要求出对角线的一侧的值再*2+对角线上的值就是答案。
#include<iostream> #include<cstdio> using namespace std; const int mod=1e9+7; const int maxx=1e5; struct Edge { long long x,y,next; Edge(int x=0,int y=0,int next=0): x(x),y(y),next(next){} }edge[maxx<<1]; long long head[maxx+1],w[maxx+1],sum[maxx+1],dad[maxx+1]; long long n,sumedge,da; long long ans; void add(int x,int y) { edge[++sumedge]=Edge(x,y,head[x]); head[x]=sumedge; } void dfs(int x) { sum[x]=w[x]; for(long long i=head[x];i;i=edge[i].next) { if(!dad[edge[i].y]) { dad[edge[i].y]=x;dfs(edge[i].y); ans=(ans%mod+sum[x]%mod*sum[edge[i].y]%mod*w[x]%mod)%mod; sum[x]=(sum[x]%mod+sum[edge[i].y]%mod)%mod; } } } int main() { freopen("asm_algo.in","r",stdin); freopen("asm_algo.out","w",stdout); scanf("%lld%lld",&n,&w[1]); for(long long i=2;i<=n;i++) { scanf("%d%d",&da,w+i);//not &w+i; add(da,i); } dfs(1); ans=ans*2%mod; for(long long i=1;i<=n;i++) ans=(ans%mod+w[i]%mod*w[i]%mod*w[i]%mod)%mod; printf("%lld\\n",ans%mod); return 0; }
以上是关于2084. Asm.Def的基本算法的主要内容,如果未能解决你的问题,请参考以下文章