ACM多校联赛7 2018 Multi-University Training Contest 7 1009 Tree

【题意概述】

  给一棵以1为根的树,树上的每个节点有一个ai值,代表它可以传送到自己的ai倍祖先,如果不存在则传送出这棵树。现在询问某个节点传送出这棵树需要多少步。

【题解】

  其实是把“弹飞绵羊”那道题从序列上搬到了树上,解法其实类似。

  我们可以用LCT维护传送的关系,若点i存在ai倍祖先,那么就把他们link起来,否则就把i与特殊节点n+1给link起来。

  询问某个点要传送多少次时,就是询问这个点到n+1有多远,我们在LCT上取出这一段,查询size即可。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cmath>
  5 #define N (100010)
  6 #define ls (c[u][0])
  7 #define rs (c[u][1])
  8 #define LL long long
  9 #define rg register
 10 using namespace std;
 11 int T,n,m,opt,cnt,tot,last[N],k[N],dfn[N],dep[N],p[N][20];
 12 struct edge{
 13     int to,pre;
 14 }e[N];
 15 char buf[20000010],*ptr=buf-1;
 16 template<typename T>
 17 inline void read(T &k)
 18 {
 19     int f=1; k=0; char c=*++ptr;
 20     while(c<‘0‘ || c>‘9‘) c==‘-‘&&(f=-1), c=*++ptr;
 21     while(c<=‘9‘ && c>=‘0‘) k=k*10+c-‘0‘, c=*++ptr;
 22     k*=f;
 23 }
 24
 25 struct Link_Cut_Tree{
 26     int top,c[N][2],fa[N],rev[N],size[N],q[N];
 27     inline void clear(){
 28         for(rg int i=1;i<=n+2;i++) c[i][0]=c[i][1]=size[i]=rev[i]=fa[i]=0;
 29     }
 30     inline void pushdown(int u){
 31         if(rev[u]) rev[ls]^=1,rev[rs]^=1,rev[u]^=1,swap(ls,rs);
 32     }
 33     inline void pushup(int u){
 34         size[u]=1;
 35         if(ls) size[u]+=size[ls];
 36         if(rs) size[u]+=size[rs];
 37     }
 38     inline bool isroot(int u){
 39         return c[fa[u]][0]!=u&&c[fa[u]][1]!=u;
 40     }
 41     inline bool which(int u){
 42         return c[fa[u]][1]==u;
 43     }
 44     void rotate(int u){
 45         int f=fa[u],gf=fa[f],wh=which(u);
 46         if(!isroot(f)) c[gf][which(f)]=u;
 47         fa[u]=gf; fa[f]=u; fa[c[u][wh^1]]=f;
 48         c[f][wh]=c[u][wh^1]; c[u][wh^1]=f;
 49         pushup(f); pushup(u);
 50     }
 51     void splay(int u){
 52         q[top=1]=u;
 53         for(int i=u;!isroot(i);i=fa[i]) q[++top]=fa[i];
 54         for(int i=top;i;i--) pushdown(q[i]);
 55         while(!isroot(u)){
 56             if(!isroot(fa[u])) rotate(which(u)==which(fa[u])?fa[u]:u);
 57             rotate(u);
 58         }
 59         pushup(u);
 60     }
 61     void access(int u){
 62         for(int son=0;u;son=u,u=fa[u])
 63             splay(u),c[u][1]=son,pushup(u);
 64     }
 65     void makeroot(int u){
 66         access(u); splay(u); rev[u]^=1;
 67     }
 68     int find(int u){
 69         access(u); splay(u);
 70         while(ls) u=ls; splay(u);
 71         return u;
 72     }
 73     void split(int x,int y){
 74         makeroot(x); access(y); splay(y);
 75     }
 76     void cut(int x,int y){
 77         int xrt=find(x),yrt=find(y);
 78         if(xrt!=yrt) return;
 79         split(x,y);
 80         if(c[y][0]==x) c[y][0]=0,fa[x]=0;
 81         pushup(y);
 82     }
 83     void link(int x,int y){
 84         int xrt=find(x),yrt=find(y);
 85         if(xrt==yrt) return;
 86         makeroot(x); fa[x]=y;
 87     }
 88 }t;
 89 void dfs(int x,int fa){
 90     dfn[x]=++cnt; dep[x]=dep[fa]+1; p[x][0]=fa;
 91     int tmp=log2(dep[x]);
 92     for (int i=1;i<=tmp;i++) p[x][i]=p[p[x][i-1]][i-1];
 93     for(rg int i=last[x];i;i=e[i].pre) dfs(e[i].to,x);
 94 }
 95 inline int anc(int x,int y){
 96     for(rg int i=0;i<=17;i++) if(y&(1<<i)) x=p[x][i];
 97     return x;
 98 }
 99 inline void Pre(){
100     for(rg int i=1;i<=n;i++) last[i]=0;
101     cnt=tot=0;
102     t.clear();
103 }
104 int main(){
105     fread(buf, 1, sizeof(buf), stdin);
106     read(T);
107     while(T--){
108            read(n);
109            Pre();
110           for(rg int i=2;i<=n;i++){
111             int fa; read(fa);
112                 e[++tot]=(edge){i,last[fa]}; last[fa]=tot;
113         }
114         dfs(1,0);
115 //        for(rg int i=1;i<=n;i++) printf("%d ",dep[i]); puts("dep");
116             for(rg int i=1;i<=n;i++){
117                 read(k[i]);
118             if(k[i]>=dep[i]) t.link(dfn[i],n+1);
119             else t.link(dfn[i],dfn[anc(i,k[i])]);
120         }
121             read(m);
122             while(m--){
123                 int opt; read(opt);
124                 if(opt==1){
125                     int x; read(x);
126                     x=dfn[x];
127                 t.makeroot(x); t.access(n+1); t.splay(n+1);
128                 printf("%d\n",t.size[n+1]-1);
129             }
130             else{
131                    int x,y; read(x); read(y);
132                    if(k[x]>=dep[x]&&y>=dep[x]) continue;
133                    if(k[x]>=dep[x]) t.cut(dfn[x],n+1);
134                 else t.cut(dfn[x],dfn[anc(x,k[x])]);
135                 k[x]=y;
136                 if(k[x]>=dep[x]) t.link(dfn[x],n+1);
137                 else t.link(dfn[x],dfn[anc(x,k[x])]);
138             }
139         }
140     }
141     return 0;
142 }

原文地址:https://www.cnblogs.com/DriverLao/p/9471119.html

时间: 2024-08-11 12:37:37

ACM多校联赛7 2018 Multi-University Training Contest 7 1009 Tree的相关文章

2018 Nowcoder Multi-University Training Contest 2

Practice Link A. run 题意: 白云每次可以移动\(1\)米或者\(k\)米,询问移动的米数在\([L, R]\)范围内的方案数有多少. 思路: \(dp[i][2]\)表示到第\(i\)米,是通过\(1\)米的方式过来的还是\(k\)米的方式过来的,递推即可. 代码: #include <bits/stdc++.h> using namespace std; #define N 100010 const int p = 1e9 + 7; int f[N][2], g[N];

2018 Nowcoder Multi-University Training Contest 1

Practice Link J. Different Integers 题意: 给出\(n\)个数,每次询问\((l_i, r_i)\),表示\(a_1, \cdots, a_i, a_j, \cdots, a_n\)中有多少个不同的数. 思路: 先分别离线求出\(a_1, \cdots a_i\)以及\(a_j, \cdots, a_n\)中有多少个不同的数. 再考虑有多少个数既在\([1, i]\)中也在\([j, n]\)中,再离线做一次. 考虑一个数第一次出现的时候,那么这个数下一次出现

2018 Nowcoder Multi-University Training Contest 5

Practice Link A. gpa 题意: 有\(n\)门课程,每门课程的学分为\(s_i\),绩点为\(c_i\),要求最多删除\(k\)门课程,使得gpa最高. gpa计算方式如下: \[ \begin{eqnarray*} gpa = \frac{\sum s_ic_i}{\sum s_i} \end{eqnarray*} \] 思路: 首先删去的课程越多,gpa肯定不会变得更差. 所以我们肯定是删去\(k\)门课程. 考虑二分答案,check的时候要满足: \[ \begin{eq

2015 HDU 多校联赛 5317 RGCDQ 筛法求解

2015 HDU 多校联赛 5317 RGCDQ 筛法求解 题目  http://acm.hdu.edu.cn/showproblem.php? pid=5317 本题的数据量非常大,測试样例多.数据量大, 所以必须做预处理.也就是用筛法求出全部的F[x],将全部F[x] 打印出来发现.事实上结果不大,最大的数值是7.所以对于每一个区间询问, 直接暴力求取有多少个 1 2 3 4 5 6 7 就可以,从大到小查找.假设出现2个以上 3-7 的数值,那么最大公约数就是该数字. 假设没有出现两个反复

2015 HDU 多校联赛 5326 Work

2015 HDU 多校联赛 5326 Work 题目: http://acm.hdu.edu.cn/showproblem.php?pid=5326 这题应该是本周二多校赛中,最简单的一道题目了. 解题思路: 就是回根. 用一个数组 root[i] = j 表示 i 的上级是 j , 对于每个输入的关系都做这样的处理.然后遍历每个编号直到root[i] 的结果为0 (因为根没有上级,所以根为0),在往根回退的过程中,用一个数组 cnt[i] 表示经过i这个点的次数. 最后就是遍历 cnt[i],

[2015hdu多校联赛补题]hdu5371 Hotaru&#39;s problem

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5371 题意:把一个数字串A翻过来(abc翻过来为cba)的操作为-A,我们称A-AA这样的串为N-sequence,现在给你一个数字串,问你这个串中最长的N-sequence子串长度 解:可以想到A-A是一个回文串,-AA也是一个回文串,那么首先Manacher跑一遍求出所有回文子串 可以想到任意两个互相覆盖的回文子串都可以表示成N-sequence 然后有三种搞法: 1.时间复杂度O(N*logN

2015 HDU 多校联赛 5363 Key Set

2015 HDU 多校联赛 5363 Key Set 题目: http://acm.hdu.edu.cn/showproblem.php?pid=5363 根据前面给出的例子,得出求解公式 fn = 2^(n-1) - 1, 数据量大,实际就是求幂次方. 可用分治法求解,复杂度O(nlogn) // 分治法求快速幂 #include <bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int MO

[2015hdu多校联赛补题]hdu5348 MZL&#39;s endless loop

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5348 题意:给你一个无向图,要你将无向图的边变成有向边,使得得到的图,出度和入度差的绝对值小于等于1,如果无解输出-1 解:考虑奇数度的点一定会成对出现(因为所有度数和肯定是偶数个->因为一条边产生两度~),那么我们可以将奇数度的点两两一连消除掉(两奇数度点的出度入读差的绝对值都为1, 路径上的点的差绝对值为0) 然后偶数度的点可以成环,那么可以搜出所有的环 1 /* 2 * Problem: 3

hdu 5344 (多校联赛) MZL&#39;s xor --- 位运算

here:    首先看一下题吧:题意就是让你把一个序列里所有的(Ai+Aj) 的异或求出来.(1<=i,j<=n) Problem Description MZL loves xor very much.Now he gets an array A.The length of A is n.He wants to know the xor of all (Ai+Aj)(1≤i,j≤n) The xor of an array B is defined as B1 xor B2...xor B