5286. 【NOIP2017提高A组模拟8.16】花花的森林 (Standard IO)

Time Limits: 1000 ms Memory Limits: 131072 KB

Description

Input

Output

Sample Input

3

1 2 3

1 2

1 3

2

1

Sample Output

6

9

6

Data Constraint

Hint

题解

我们考虑倒着做,即最开始是一个包含了 n 棵只有一个点的树的森林,然后不断加边,最后得到一棵完整的树。这样我们只需能够快速求出两棵树合并后得到新树的直径即可解决这个问题。

设合并的两棵树是 Ta 和 Tb,合并后形成的新树是 T。记 Ta 的直径的两端点为 ua 和va,Tb 的直径的两端点为 ub 和 vb,则 T 的直径的两端点一定 ∈ {ua, ub, va, vb}(由反证法不难证明)。这样我们只需维护每个块的直径及直径的两端点。在合并两个块时,我们只需暴力求出 4 个点对之间的路径长度,进行比较即可。

在这个过程中我们需要除以原来两块的直径。在模的意义下,除以一个数等价于乘以这个数的逆元。时间复杂度为O(n2),期望得分 60 − 80 分。

我们考虑改进上面的做法,虽然有加边、删边操作,但事实上我们要求的点对之间的路

径长度都是原树上的路径。故我们可以通过对原树进行倍增预处理,每次在 O(logn) 的时间内求得点对间的最近公共祖先(lca),从而得到点对间的路径长度。

时间复杂度为O(nlogn),期望得分 100 分。

代码

#include<cstdio>
#include<algorithm>
#include<vector>
#define ll long long
#define mo 1000000007
#define UP 20
#define N 100010
using namespace std; struct point{
long x,y;
void make(long x,long y)
{
this->x=x;
this->y=y;
}
}root[N],b[N]; long n; long fa[N][UP+1],dep[N],father[N],w[N],a[N],len[N],c[N],out[N];
void init()
{ long i,j;
for(i=1;i<=n;i++){
for(j=1;(1<<j)<=dep[i];j++)
fa[i][j]=fa[fa[i][j-1]][j-1];
father[i]=i;
root[i].make(i,i);
w[i]=a[i];
}
} long lca(long x,long y)
{ long up,xx=x,yy=y;
if(dep[x]>dep[y])
swap(x,y);
for(up=UP;up>=0;up--)
if(dep[y]-(1<<up)>=dep[x])
y=fa[y][up];
up=UP;
while(x!=y){
while(up>=0&&fa[x][up]==fa[y][up])
up--;
if(up<0)break;
x=fa[x][up];
y=fa[y][up];
up--;
}
if(x==y)
return len[xx]+len[yy]-2*len[x]+a[x];
else
return len[xx]+len[yy]-2*len[fa[x][0]]+a[fa[x][0]];
} vector<long>map[N];
bool ok[N];
void dfs(long now)
{ long i,to,next;
ok[now]=true;
for(i=0;i<map[now].size();i++){
to=map[now][i];
if(!ok[to]){
fa[to][0]=now;
dep[to]=dep[now]+1;
len[to]=a[to]+len[now];
dfs(to);
}
}
} long ksm(long a,long b)
{
if(b>1)
if(b&1)
return (ll)ksm((ll)a*a%mo,b>>1)*a%mo;
else
return ksm((ll)a*a%mo,b>>1);
else return a;
} long cha(long x)
{
return (father[x]==x)?x:father[x]=cha(father[x]);
}
void bin(long x,long y)
{
father[cha(x)]=cha(y);
} int main()
{ long i,xx,yy,r1,r2,r3,r4,w1,w2,w3,w4,maxx;
long long ans=1;
scanf("%ld",&n);
for(i=1;i<=n;i++){
scanf("%ld",&a[i]);
ans=ans*a[i]%mo;
}
out[n]=ans;
for(i=1;i<n;i++){
scanf("%ld%ld",&xx,&yy);
b[i].make(xx,yy);
map[xx].push_back(yy);
map[yy].push_back(xx);
}
dfs(1);
init();
for(i=1;i<n;i++)
scanf("%ld",&c[i]);
for(i=n-1;i>=1;i--){
xx=cha(b[c[i]].x);
yy=cha(b[c[i]].y);
r1=root[cha(xx)].x;
r2=root[cha(xx)].y;
r3=root[cha(yy)].x;
r4=root[cha(yy)].y;
w1=lca(r1,r3);
w2=lca(r1,r4);
w3=lca(r2,r3);
w4=lca(r2,r4);
maxx=max(w1,max(w2,max(w3,max(w4,max(w[xx],w[yy])))));
ans=ans*ksm(w[xx],mo-2)%mo*ksm(w[yy],mo-2)%mo*maxx%mo;
bin(xx,yy);
if(maxx==w1)
root[cha(xx)].make(r1,r3);
if(maxx==w2)
root[cha(xx)].make(r1,r4);
if(maxx==w3)
root[cha(xx)].make(r2,r3);
if(maxx==w4)
root[cha(xx)].make(r2,r4);
if(maxx==w[xx])
root[cha(xx)].make(r1,r2);
if(maxx==w[yy])
root[cha(xx)].make(r3,r4);
w[cha(xx)]=maxx;
out[i]=ans;
}
for(i=1;i<=n;i++)
printf("%ld\n",out[i]);
return 0;
}

JZOJ 5286. 【NOIP2017提高A组模拟8.16】花花的森林 (Standard IO)的更多相关文章

  1. JZOJ 【NOIP2017提高A组模拟9.14】捕老鼠

    JZOJ [NOIP2017提高A组模拟9.14]捕老鼠 题目 Description 为了加快社会主义现代化,建设新农村,农夫约(Farmer Jo)决定给农庄里的仓库灭灭鼠.于是,猫被农夫约派去捕 ...

  2. [JZOJ 100026] [NOIP2017提高A组模拟7.7] 图 解题报告 (倍增)

    题目链接: http://172.16.0.132/senior/#main/show/100026 题目: 有一个$n$个点$n$条边的有向图,每条边为$<i,f(i),w(i)>$,意 ...

  3. 【NOIP2017提高A组模拟9.7】JZOJ 计数题

    [NOIP2017提高A组模拟9.7]JZOJ 计数题 题目 Description Input Output Sample Input 5 2 2 3 4 5 Sample Output 8 6 D ...

  4. JZOJ 100029. 【NOIP2017提高A组模拟7.8】陪审团

    100029. [NOIP2017提高A组模拟7.8]陪审团 Time Limits: 1000 ms  Memory Limits: 131072 KB  Detailed Limits   Got ...

  5. JZOJ 5328. 【NOIP2017提高A组模拟8.22】世界线

    5328. [NOIP2017提高A组模拟8.22]世界线 (File IO): input:worldline.in output:worldline.out Time Limits: 1500 m ...

  6. JZOJ 5329. 【NOIP2017提高A组模拟8.22】时间机器

    5329. [NOIP2017提高A组模拟8.22]时间机器 (File IO): input:machine.in output:machine.out Time Limits: 2000 ms M ...

  7. JZOJ 5307. 【NOIP2017提高A组模拟8.18】偷窃 (Standard IO)

    5307. [NOIP2017提高A组模拟8.18]偷窃 (Standard IO) Time Limits: 1000 ms Memory Limits: 262144 KB Description ...

  8. JZOJ 5305. 【NOIP2017提高A组模拟8.18】C (Standard IO)

    5305. [NOIP2017提高A组模拟8.18]C (Standard IO) Time Limits: 1000 ms Memory Limits: 131072 KB Description ...

  9. 【NOIP2017提高A组模拟9.17】信仰是为了虚无之人

    [NOIP2017提高A组模拟9.17]信仰是为了虚无之人 Description Input Output Sample Input 3 3 0 1 1 7 1 1 6 1 3 2 Sample O ...

随机推荐

  1. thinking in java学习笔记:14章 类型信息

    14.2 Class 对象 https://github.com/zhaojiatao/javase 1.什么是Class对象,Class对象是用来做什么的? Class对象是java程序用来创建类的 ...

  2. python实现个人信息随机生成

    """ 生成随机姓名.电话号码.身份证号.性别.应行卡号.邮箱 """ import random from firstname impor ...

  3. maven-assembly-plugin 打包包含多余依赖问题一则

    有同事反馈自己maven-assembly-plugin打的包里面多了很多mvn dependency:tree中没有的jar. 我当时只是试着把他的maven-assembly-plugin更新到了 ...

  4. jQ给下拉框绑定事件,为什么要绑定在框(select标签)上,而不是绑定在选项(option标签)上

    这是我在学习锋利的 jquery 书中 5.1.4 的代码时遇到的一个小问题,源代码如下: <head> <style type="text/css"> * ...

  5. @EnableGlobalMethodSecurity(prePostEnabled = true)

    http://www.bubuko.com/infodetail-2243816.html

  6. Servlet的Cookie对象

    Cookie的介绍:Cookie 定义:Cookie 用于浏览器端的数据存储,解决了不同请求之间需要数据共享的问题.例如,可以将用户的登录信息接收并设置为Cookie,对其进行相关操作以使得用户在特定 ...

  7. 线程中start和run方法的区别

    先说java中实现多线程常用的两种方式:   1:继承Thread类,并重写run()方法   2:实现Runnable接口,实现run方法实际上Thread类也是实现了Runnable接口 [Jav ...

  8. C++类和对象到底是什么意思?

    C++ 是一门面向对象的编程语言,理解 C++,首先要理解类(Class)和对象(Object)这两个概念. C++ 中的类(Class)可以看做C语言中结构体(Struct)的升级版.结构体是一种构 ...

  9. TPO3-2 Depletion of Ogallala Aquifer

    Estimates indicate that the aquifer contains enough water to fill Lake Huron, but unfortunately, und ...

  10. 在CentOS安装CMake (CentOS7 64位适用)

    在CentOS安装CMake 转自:http://www.cnblogs.com/mophee/archive/2013/03/19/2969456.html 一.环境描述 1.系统:CentOS 6 ...