JZOJ 5286. 【NOIP2017提高A组模拟8.16】花花的森林 (Standard IO)
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)的更多相关文章
- JZOJ 【NOIP2017提高A组模拟9.14】捕老鼠
JZOJ [NOIP2017提高A组模拟9.14]捕老鼠 题目 Description 为了加快社会主义现代化,建设新农村,农夫约(Farmer Jo)决定给农庄里的仓库灭灭鼠.于是,猫被农夫约派去捕 ...
- [JZOJ 100026] [NOIP2017提高A组模拟7.7] 图 解题报告 (倍增)
题目链接: http://172.16.0.132/senior/#main/show/100026 题目: 有一个$n$个点$n$条边的有向图,每条边为$<i,f(i),w(i)>$,意 ...
- 【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 ...
- JZOJ 100029. 【NOIP2017提高A组模拟7.8】陪审团
100029. [NOIP2017提高A组模拟7.8]陪审团 Time Limits: 1000 ms Memory Limits: 131072 KB Detailed Limits Got ...
- JZOJ 5328. 【NOIP2017提高A组模拟8.22】世界线
5328. [NOIP2017提高A组模拟8.22]世界线 (File IO): input:worldline.in output:worldline.out Time Limits: 1500 m ...
- JZOJ 5329. 【NOIP2017提高A组模拟8.22】时间机器
5329. [NOIP2017提高A组模拟8.22]时间机器 (File IO): input:machine.in output:machine.out Time Limits: 2000 ms M ...
- JZOJ 5307. 【NOIP2017提高A组模拟8.18】偷窃 (Standard IO)
5307. [NOIP2017提高A组模拟8.18]偷窃 (Standard IO) Time Limits: 1000 ms Memory Limits: 262144 KB Description ...
- 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 ...
- 【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 ...
随机推荐
- 吴裕雄--天生自然C语言开发:错误处理
#include <stdio.h> #include <errno.h> #include <string.h> extern int errno ; int m ...
- day34-进程
#进程是程序的运行,程序不运行不产生进程. #1.进程的并行与并发: # 并行:是指两者同时执行,比如赛跑,两人都在不停的往前跑.(资源够用,比如三个线程,四核的cpu) # 并发:是指资源有限的情况 ...
- Windows下 webstorm安装tomcat配置svn并使用
先附上所需要的软件的下载地址:https://pan.baidu.com/s/1c2ripd2 1.下载并安装jdk以及配置jdk的环境变量 1)下载jdk,选择安装目录安装,我选择的是默认路径,安装 ...
- Linux_centos安装后无法进入图形界面
问题 直接默认进入字符界面 root之后init 5也没用 解决方法 出现问题的原因在于安装时选择了最小安装,如图所示
- 网页中常见返回HTTP状态码含义
在日常网页浏览的过程中大家经常会碰到400,403,404,500,502等HTTP状态码,这些状态码对于一般用户来说出现什么都是一样的,反正就是页面打不开了,但是作为网站开发人员或者从事相关工作者认 ...
- FPGA大疆考试准备内容
1.寄存器与锁存器 锁存器:电平触发的存储单元,在有效电平时间里可以多次改变数据. 优点: 占触发器资源少,缺点是容易产生毛刺.(附上去毛刺的方法:格雷码计数器(*https://blog.cs ...
- 用两个栈实现一个队列(C++)
分析 栈:后进先出 队列:先进先出 要使用两个栈实现队列(先进先出),主要思路是 1.插入一个元素:直接将元素插入stack1即可. 2.删除一个元素:当stack2不为空时 ,直接弹出栈顶元素,当s ...
- C++中字符串的表示与转换
转换总结 1.char*转string:可以直接赋值. 2.char[]转string:可以直接赋值. 3.char*转char[]:不能直接赋值,可以循环char*字符串逐个字符赋值,也可以使用st ...
- Nginx笔记总结二:Nginx编译参数
-prefix= 安装路径-with-http_ssl_module ...
- js中escape的用法
escape() 方法,它用于转义不能用明文正确发送的任何字符.比如,电话号码中的空格将被转换成字符 %20,从而能够在 URL 中传递这些字符. var s="http://local ...