JZOJ.5286【NOIP2017模拟8.16】花花的森林

Description

Input

Output

Sample Input

3
1 2 3
1 2
1 3
2
1

Sample Output

6
9
6

Data Constraint

Hint

题目大意就是要求删边和计算直径。

很明显每次删边后两边BFS计算直径必会超时,但我们可以通过lca和预处理节点到根节点的距离来快速计算,但删边后lca很可能有所变化,重新预处理lca的信息又太慢了。

我们可以试着逆向

即正着删边看成反着添边。

这样子我们可以发现是等效的。

一开始每棵树的直径就是该点的权值。

当我们连上一条边,把两棵子树合并的时候,我们可以证明,这棵新的子树的直径的两个端点一定是合并前那两个子树四个端点中的两个,所以我们只要将四个端点两两配对比较一下距离我们就可以得出新的子树的直径。这里是计算树的距离我们仍然采用LCA。但这里我们惊奇地发现当两个棵子树合并的时候,它们的LCA一定是存在的,并且也是原图中的LCA(而删边很可能导致某两个点没有了LCA),于是我们可以预处理整棵树的LCA出来。至于两棵子树的合并,我们可以一开始就预处理节点的深度和到根节点的距离,这样在合并的时候就方便将深度深的节点的fa指向深度浅的节点。

计算ans也就直接乘上新的子树的直径再除以之前的两棵子树的直径,mod的话取个逆就好了。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<ctime>
  8 #define N 200005
  9 #define mo 1000000007
 10 using namespace std;
 11 int head[N],next[N*2],to[N*2],va[N],up[N][30],deep[N],x[N],y[N],n,f[N],num,qwq[N],sx[N],sy[N],fa[N],ma;
 12 long long ans,dis[N],an[N];
 13 long long kuai(long long a,int b){
 14     long long d=1;
 15     long long qwq=a;
 16     while (b){
 17         if (b&1) d=d*qwq%mo;
 18         qwq=qwq*qwq%mo;
 19         b>>=1;
 20     }
 21     return d;
 22 }
 23 void add(int u,int v){
 24     num++;
 25     next[num]=head[u];
 26     to[num]=v;
 27     head[u]=num;
 28     num++;
 29     next[num]=head[v];
 30     to[num]=u;
 31     head[v]=num;
 32 }
 33 void updata(int u){
 34     dis[u]=dis[fa[u]]+va[u];
 35     up[u][0]=fa[u];
 36     for (int i=1;i<=25;i++)
 37      up[u][i]=up[up[u][i-1]][i-1];
 38     for (int i=head[u];i;i=next[i]){
 39         int v=to[i];
 40         if (v!=fa[u])
 41          deep[v]=deep[u]+1,fa[v]=u,updata(v);
 42     }
 43 }
 44 int lca(int u,int v){
 45     if (deep[u]<deep[v]) swap(u,v);
 46     for (int i=20;i>=0;i--)
 47      if (deep[v]<=deep[up[u][i]])
 48       u=up[u][i];
 49     if (u==v) return u;
 50     for (int i=20;i>=0;i--)
 51      if (up[u][i]!=up[v][i])
 52       u=up[u][i],v=up[v][i];
 53     return up[u][0];
 54 }
 55 int find(int x){
 56     if (f[x]==x) return x;
 57     f[x]=find(f[x]);
 58     return f[x];
 59 }
 60 void work(int a,int b){
 61     if (deep[a]>deep[b]) swap(a,b);
 62     int f1=find(a),f2=find(b);
 63     f[f2]=f1;
 64     long long qaq=dis[sx[f1]],qvq=dis[sy[f1]],qoq=dis[sx[f2]],qsq=dis[sy[f2]];
 65     int t1=sx[f1],t2=sy[f1],t3=sx[f2],t4=sy[f2];
 66     int l1=lca(sx[f1],sx[f2]),l2=lca(sx[f1],sy[f2]),l3=lca(sy[f1],sx[f2]),l4=lca(sy[f1],sy[f2]),l5=lca(sx[f2],sy[f2]),l6=lca(sx[f1],sy[f1]);
 67     long long tmp3=qaq+qvq-2*dis[l6]+va[l6],tmp2=qsq+qoq-2*dis[l5]+va[l5];
 68     long long tmp1=tmp3;
 69     if (qaq+qoq-2*dis[l1]+va[l1]>tmp1) tmp1=qaq+qoq-2*dis[l1]+va[l1],sx[f1]=t1,sy[f1]=t3;
 70     if (qaq+qsq-2*dis[l2]+va[l2]>tmp1) tmp1=qaq+qsq-2*dis[l2]+va[l2],sx[f1]=t1,sy[f1]=t4;
 71     if (qvq+qoq-2*dis[l3]+va[l3]>tmp1) tmp1=qvq+qoq-2*dis[l3]+va[l3],sx[f1]=t2,sy[f1]=t3;
 72     if (qvq+qsq-2*dis[l4]+va[l4]>tmp1) tmp1=qvq+qsq-2*dis[l4]+va[l4],sx[f1]=t2,sy[f1]=t4;
 73     if (qsq+qoq-2*dis[l5]+va[l5]>tmp1) tmp1=qsq+qoq-2*dis[l5]+va[l5],sx[f1]=t3,sy[f1]=t4;
 74     ans=ans*((tmp1%mo)%mo*(kuai(tmp2,mo-2)%mo)%mo*(kuai(tmp3,mo-2)%mo)%mo)%mo;
 75     an[ma]=ans;
 76     ma--;
 77 }
 78 int main(){
 79     scanf("%d",&n);
 80     for (int i=1;i<=n;i++){
 81      scanf("%d",&va[i]);
 82      f[i]=i;
 83      sx[i]=i;
 84      sy[i]=i;
 85     }
 86     for (int i=1,u,v;i<n;i++){
 87         scanf("%d%d",&u,&v);
 88         x[i]=u;
 89         y[i]=v;
 90         add(u,v);
 91     }
 92     deep[1]=0;
 93     dis[0]=0;
 94     fa[1]=1;
 95     deep[1]=0;
 96     updata(1);
 97     for (int i=1;i<n;i++)
 98      scanf("%d",&qwq[i]);
 99     num=0;
100     ans=1;
101     for (int i=1;i<=n;i++)
102      ans=(ans*(va[i]%mo))%mo;
103     ma=n;
104     an[ma]=ans;
105     ma--;
106     for (int i=n-1;i>=1;i--){
107         work(x[qwq[i]],y[qwq[i]]);
108     }
109     for (int i=1;i<=n;i++)
110      printf("%lld\n",an[i]);
111     return 0;
112 }

神奇的代码

时间: 2024-09-29 10:57:35

JZOJ.5286【NOIP2017模拟8.16】花花的森林的相关文章

JZOJ.5287【NOIP2017模拟8.16】最短路

Description Input Output Sample Input 9 10 2 1 2 1 1 4 1 3 4 1 2 3 1 3 7 1 7 8 2 7 9 2 1 5 3 1 6 4 5 6 1 1 9 5 7  Sample Output 5 6 Data Constraint 容易发现这是一张仙人掌图(每条边最多属于一个环的无向连通图) 仙人掌图求最短路的常用处理方法是将它变成一棵树,原图里为环的点更改为该环上的点都指向该环的某个点A,然后边长就是该点到点A的最短路径. 再预处

Cisco PT模拟实验(16) 路由器重分发配置

Cisco PT模拟实验(16) 路由器重分发配置 实验目的: 掌握路由器重分发的配置方法 掌握査看通过路由重分发学习产生的路由 实验背景: 随着公司网络规模不断扩大,公司内安装了多个路由器并运行多种路由协议,其中,公司出口路由器R2与公司外的一台路由器R3连接,三层交换机与R2间运行RIPv2路由协议,R1与R2间运行静态路由协议,R2与R3间运行OSPF路由协议.现要做适当配置,实现公司内部主机与公司外部主机之间的相互通信. 技术原理: 路由重分发(Route Redistribution)

JZOJ.5281【NOIP2017模拟8.15】钦点

Description Input Output Sample Input 4 4 2 a a b b a a b b c c d d c c d d 1 1 3 3 2 2 3 1 1 3 2 2 Sample Output d d c c  d d c c  b b a a  b b a a  Data Constraint 本题时限4s. 很明显这是一道模拟题,朴素算法O(nmq)看似过得去,实际上字符串的操作是很慢的,同样对字符串赋值10w次比对数组元素赋值10w次要慢3倍以上. 实际上

JZOJ.5331【NOIP2017模拟8.23】壕游戏

Description Input Output Sample Input 6 8 2 2 4 5  1 2 4 0 2 1 3 5 0 2 3 4 1 5 1 2 5 1 0 1 4 6 4 2 2 5 6 0 4 2 1 5 5 9 2 2 6 4 5 2 Sample Output 16 Data Constraint Hint 类似于一种可撤销的贪心,不难想到这是费用流的模型. 考虑到我们实际会用到的边比实际的边少很多,我们可以动态建边,以减少空间的使用,即当流过了一条边之后再建立第二次

JZOJ.5274【NOIP2017模拟8.14】数组

Description Input Output Sample Input 输入样例1: 3 2 7 5 4 2 输入样例2: 5 3 1 5 4 3 5 5 Sample Output 输出样例1: 999999732 输出样例2: 0 Data Constraint 这个题要求乘积最小,显然我们希望乘积是负数是最好的,然后就是让这个负数的绝对值尽可能的大. 对于一堆数相乘,绝对值最小的对这个结果影响是最大的,所以我们就每次让绝对值最小的,如果是正数就加上x,负数就减去x,用个优先队列维护绝对

JZOJ.5329【NOIP2017模拟8.22】时间机器

Description Input Output Sample Input 3 2 2 1 4 2 3 5 1 1 4 2 2 5 1 3 2 1 3 1 2 4 1 3 5 1 1 3 2 2 5 1 2 2 1 2 2 1 2 1 1 2 1 1 2 2   Sample Output Yes No Yes Data Constraint Hint 很明显这是要让我们匹配,很容易想到可以二分图匹配,但是又有数量,于是我们可以网络流,但是n还是巨大,使得我们不得不想想其他办法. 我们的期望搭配

JZOJ.5305【NOIP2017模拟8.18】C

Description Input Output Sample Input 10 11 1 2 2 3 3 4 1 4 3 5 5 6 8 6 8 7 7 6 7 9 9 10  6 1 2 3 5 6 9 9 2 9 3 9 10  Sample Output 2 2 2 4 4 1  Data Constraint Hint 题意有点问题,实际上简单路径这里指的是不经过重复边的路径. 这题Tarjan缩点,然后LCA统计两点间环的个数k,答案就是2k个路径. 1 #include<iostr

JZOJ.5285【NOI2017模拟8.16】排序

Description Input Output Sample Input 5 2 1 5 3 4 Sample Output 5 4 3 1 2 Data Constraint Hint 感觉像是某年NOIP的双栈排序的弱化版...... 这题要求字典序最大,我们采用贪心做法,我们可以证明这是正确的. 考虑每一位的数字,我们尽可能地让它大,很明显第一位一定能保证是最大值. 那么对于第二位我们当然想让它为第二大的数字,如果这个数字不在栈里面,那么我们可以等待它进栈后再弹出,但如果已经在栈里面,但

JZOJ.5306【NOIP2017模拟8.18】棋盘游戏

Description 这个游戏上在一个无限大的棋盘上, 棋盘上只有一颗棋子在位置(x,y)(x,y>=0)棋盘的左下角是(0,0)Amphetamine每次都是第一个移动棋子,然后Amphetamine与Alphago轮流移动.每一轮可以做以下三种中的一种操作: 1)在同一行,将棋子从当前位置向左移动任意格:2)在同一列,将棋子从当前位置向下移动任意格: 3)将棋子从当前位置向下移动k格再向左移动k格(k为任意正整数,且要满足移动后的棋子仍然在棋盘上) 第一个不能在棋盘上移动的人比赛算输(因为