bst
【问题描述】
二叉查找树是一种特殊的二叉树(每个节点最多只有两个儿子的树)。树的每个节点上存有一个唯一的值,并且满足:这个节点的左子树内所有点的值都比这个节点的值小,且右子树内所有点的值都比这个节点的值要大。
对于一棵二叉查找树T,我们可以将一个值为x的新点插入T中,且保持树的性质。
算法如下:
需要将x插入树T时,执行insert(x, T.root) 。
现在有N个数需要插入一棵空树中。给定插入序列,请在每个元素被插入之后,输出所有节点的深度总和(根的深度为0)。
【输入格式】
输入的第一行一个整数 n,表示序列长度。
以下 n 行是序列中的数字,这些数字是各不相同的,在[1, n]区间。
【输出格式】
输出 n 行,第 i 行整数表示第 i 个数插入树后,至这个节点的节点深度总和。
【样例输入】
8
3
5
1
6
8
7
2
4
【样例输出】
0
1
2
4
7
11
13
15
【数据规模与约定】
对于 50%的数据, 满足N ≤ 1000
对于100%的数据,满足N ≤ 3 ∗ 10^5 。
Solution:
双向链表+DP。(也可以说是个模拟)
和字面意思上一样是一个treap。
我们考虑:当x=a[i]被插入的时候,假设T(二叉搜索树)中比x小的最大元素是p,比x大的最小元素是q。显然,p,q一定相连(可以证明)。
(证明:p,q之间不存在其他元素,谁在父亲取决于谁先插入。)
我们设f[i]表示x插入的深度,可得f[i]=Max(f[p],f[q])+1。
即转化为求p,q。
怎么求呢?
可以用双向链表存1~n,每次删除一个元素,删除时的前驱和后继就是p,q。
这个问题就解决了。(其实也就是模拟一下treap)
Other:
现场还有大佬对着排序数组按时间戳建笛卡尔树A了此题,大概不会打...
1 #include <iostream> 2 3 #define MAXN 300005 4 5 int n; 6 int a[MAXN]; 7 int prev[MAXN], next[MAXN]; 8 int u[MAXN], v[MAXN]; 9 int deep[MAXN]; 10 11 int main(void) 12 { 13 14 scanf("%d", & n); 15 for (int i = 1; i <= n; ++i) 16 scanf("%d", a + i); 17 18 for (int i = 1; i <= n; ++i) 19 { 20 prev[i] = i - 1; 21 next[i] = i + 1; 22 } 23 24 int x; 25 for (int i = n; i > 1; --i) 26 { 27 x = a[i]; 28 u[x] = prev[x]; 29 v[x] = next[x]; 30 next[prev[x]] = next[x]; 31 prev[next[x]] = prev[x]; 32 } 33 34 long long sum = 0; 35 for (int i = 1; i <= n; ++i) 36 { 37 x = a[i]; 38 39 if ((u[x] >= 1) && (u[x] <= n)) 40 if (deep[x] < deep[u[x]] + 1) 41 deep[x] = deep[u[x]] + 1; 42 if ((v[x] >= 1) && (v[x] <= n)) 43 if (deep[x] < deep[v[x]] + 1) 44 deep[x] = deep[v[x]] + 1; 45 46 sum += deep[a[i]]; 47 48 printf("%lld ", sum); 49 } 50 51 return 0; 52 }
ctsc:
【问题描述】
n 人参加信息学竞赛,共有 m 道题。现在比赛已经结束,评分正在进行中,对于已经结束评测的试题,已知每名考生这道题的答案是否正确,对于未结束评测的试题,只知道每名考生是否提交答案。每个题分数固定,提交正确的答案的考生可以得到这一题的分数,分数越高排名越靠前,分数相同编号小的考生排名靠前。这 n 人中,排名最靠前的 s 人将获得入选代表队的资格,而这 s 个中将通过最终的科学委员会面试选出其中的 t 个人。输入当前的评测信息(包括是否ᨀ交,以及已经评测部分的是否正确)以及每道题的分值,问最终的 t 人代表队共有多少种组队的可能。
【输入格式】
输入文件第一行是 m,接下去 m 行每行一个整数来表示每道题目的分值(整数是正的表示该题已经评测,否则表示该题尚未评测,该题目的分值为这个整数的绝对值)。然后是一个整数 n,接下去是一个 n 行 m 列的字母阵,字母阵只包含 YN 两种字母(Yes or No),如果第 i 题已经完成评测,那么这个字母矩阵中第 j 行第 i 列的表示第 j 名选手的第 i 题是否已经得分;如果第 i 题尚未完成评测,那么这个字母矩阵中第 j 行第 i 列的表示第 j 名选手的第 i 题是否提交了解答。接下来两个整数s,t如题意。
【输出格式】
输出文件只有一行,即为最终的 t 人代表队的组队方案数。
【样例输入】
2
1
-10
4
NY
YN
YN
YN
3
2
【样例输出】
5
【数据规模与约定】
对于100%的数据, 满足1 ≤N, M ≤ 50。
Solution:
Other:
据说是最简单的组合数呢。
考场玩了一个多小时也没证明出来。
所以留坑...?
1 #include <cstring> 2 #include <vector> 3 #include <string> 4 #include <algorithm> 5 #include <list> 6 #include <set> 7 #include <queue> 8 #include <stack> 9 #include <sstream> 10 #include <numeric> 11 #include <functional> 12 #include <utility> 13 #include <bitset> 14 #include <iostream> 15 #include <cmath> 16 #include <map> 17 18 using namespace std; 19 20 #define MAXM 60 21 #define MAXN 60 22 23 #define DEBUG 0 24 25 typedef long int LINT; 26 typedef long long INT64; 27 28 typedef struct stProblem { 29 int score; 30 int state; 31 } tProblem; 32 tProblem problem[MAXM]; 33 34 typedef struct stOIer { 35 int id; 36 LINT max; 37 LINT min; 38 } tOIer; 39 tOIer oier[MAXN]; 40 41 int p[MAXN]; 42 43 int n, m, s, t; 44 45 INT64 ans; 46 47 INT64 calc_c(LINT m, LINT n) { 48 if ((m < 0) || (n < 0)) 49 return 0; 50 if (m == 0) 51 return 1; 52 if (n == 0) 53 return 0; 54 55 if (m > n) 56 return 0; 57 if (m == n) 58 return 1; 59 60 INT64 result = 1; 61 for (int i = 0; i < n - m; ++i) { 62 result = result * (n - i) / (1 + i); 63 } 64 65 return result; 66 } 67 68 void bubble_sort() { 69 int bubble_sort_cmp(tOIer *a, tOIer *b); 70 71 for (int i = 0; i < n - 1; ++i) 72 for(int j = n - 1; j > i; --j) 73 if (bubble_sort_cmp(oier + (j - 1), oier + j) < 0) 74 swap(oier[j - 1], oier[j]); // Defined in algorithm.h. 75 } 76 77 int bubble_sort_cmp(tOIer *a, tOIer *b) { 78 if (a->max < b->max) { 79 return -1; 80 } else if (a->max == b->max) { 81 return 0; 82 if (a->id > b->id) 83 return -1; 84 else 85 return 1; 86 } else { 87 return 1; 88 } 89 } 90 91 int main(int argc, char *argv[]) { 92 scanf("%d ", & m); 93 94 LINT temp_score; 95 for (int i = 0; i < m; ++i) { 96 scanf("%ld ", & temp_score); 97 if (temp_score > 0) { 98 problem[i].score = temp_score; 99 problem[i].state = 1; 100 } else { 101 problem[i].score = -temp_score; 102 problem[i].state = 0; 103 } 104 } 105 106 scanf("%d ", & n); 107 108 char temp_state[MAXM]; 109 for (int i = 0; i < n; ++i) { 110 oier[i].id = i; 111 112 scanf("%s ", temp_state); 113 for (int j = 0; j < m; ++j) 114 if (problem[j].state) { 115 if ('Y' == temp_state[j]) { 116 oier[i].max += problem[j].score; 117 oier[i].min += problem[j].score; 118 } 119 } else { 120 if ('Y' == temp_state[j]) 121 oier[i].max += problem[j].score; 122 } 123 } 124 125 scanf("%d ", & s); 126 scanf("%d ", & t); 127 128 bubble_sort(); // Max Score DESC Id ASC. 129 130 for (int i = 0; i < n; ++i) 131 for (int j = 0; j < i; 132 p[i] += ((oier[j].min > oier[i].max) 133 || ((oier[j].min == oier[i].max) && (oier[j].id < oier[i].id))), ++j) 134 ; 135 136 #if DEBUG 137 for (int i = 0; i < n; ++i) 138 printf("%d(ID %d) : MAX(%d), MIN(%d) P(%d) ", i, 139 oier[i].id, oier[i].max, oier[i].min, p[i]); 140 printf(" "); 141 #endif 142 143 int k_min, k_max; 144 ans = 0; 145 for (int i = t - 1; i < n; ++i) { 146 if (p[i] > s - 1) 147 break; 148 149 k_min = max(p[i] - s + t, 0); 150 k_max = min(p[i], t - 1); // t - 1 - k >= 0 151 152 #if DEBUG 153 printf("STATE %d, MIN(%d), MAX(%d) ", i, k_min, k_max); 154 #endif 155 156 for (int k = k_min; k <= k_max; ++k) 157 ans += calc_c(k, p[i]) * calc_c(t - 1 - k, i - p[i]); 158 } 159 160 printf("%lld ", ans); 161 }
//std画风有点神奇我也不太懂...留坑等待更新自己der
history
【问题描述】
zhx 不喜欢研究历史,但是 dhh 是历史大师。
【问题描述】
历史学家dhh正在研究一个奇怪的王国的历史。当前阶段的任务是研究该国的交通。
根据这个奇怪的王国的史书记载,史书开始记载前这个王国有n个城市(城市从0开始标号),但所有城市之间都没有道路相连。
每一年,在位的国王会修建一条双向道路x<->y(x!=y),一条道路可能被修建多次。
而在这之间,国王会计划进行若干次旅行。对于计划进行的一次旅行st->ed,如果当时能完成这次旅行,而t年前不能完成这次旅行,那么国王会对之前的建设成果感到满意,否则他会很生气,并在他感到满意之前(包括使他满意的那次旅行)都让史官记录下错误的信息,怎么样得到正确信息将在输入格式中描述。
当然在这些年中也发生了若干次国王的交替,而每个国王的c值不一定相同,但在国王在位期间c值不会改变(初始国王的c值为0,其他的c值可通过记载得到),新上位的国王开始处于不生气的状态。
请根据史书帮助DHH得出国王每次对于计划旅行是否满意,从而使DHH能够研究该国的交通。
【输入格式】
输入多组数据,到EOF结束。
每组数据第一行两个整数n,m,表示初始城市数和史书记载的内容数。
接下来m行,每行是以下三种格式之一:
1.K v,表示国王交替,如果被替换的国王是生气的(即这个是错误信息),那么新国王的c值为 v+被替换的国王的值,否则新国王的c值为v。
2.R x y,表示史书上记载的是国王修建了x<->y的道路,如果这是错误信息,那么真实信息为 (x+c)%n <-> (y+c)% n的道路。
3.T st ed t,表示国王计划进行的一次st->ed的旅行,且比较的是t年前的情况(国王可能会和史书开始记载以前的情况比较),如果这是错误信息,那么真实信息为国王计划进行的一次 (st+c)%n -> (ed+c)%n 的旅行,且比较的是(t+c)%n年前的情况。
注意只有遇到R操作才会使年份的计数+1。
【输出格式】
每组数据对于每个T的记录输出一行,如果此次计划旅行令国王满意,则输出Y,否则输出N。样
【样例输入】
3 7 R 0 1 T 0 1 1 K 1 R 0 1 T 0 1 1 R 0 1 T 1 2 0
【样例输出】
Y N Y
【数据规模与约定】
n,m ≤ 3 × 10^5 , 0 ≤ v,x,y,st,ed < n , 0 ≤ t < m,数据组数≤ 10
Solution:
// blog坑填不完了。。。先贴std,不然空着好像不太好
1 #include <algorithm> 2 #include <cstdio> 3 #include <cstring> 4 5 using namespace std; 6 7 #define rep(i, n) for (int i = 0; i < n; ++i) 8 9 const int MaxN = 300005; 10 11 int f[MaxN], g[MaxN], h[MaxN]; 12 int n, m; 13 long long c; 14 bool ans; 15 char opr[50000]; 16 17 int get(int x, int t) { 18 while (f[x] >= 0 && g[x] <= t) x = f[x]; 19 return x; 20 } 21 22 void merge(int x, int y, int t) { 23 x = get(x, t); 24 y = get(y, t); 25 if (x != y) { 26 if (h[x] > h[y]) swap(x, y); 27 f[x] = y, g[x] = t; 28 h[y] += (h[x] == h[y]); 29 } 30 } 31 32 int main(void) { 33 freopen("history.in","r",stdin); 34 freopen("history.out","w",stdout); 35 int t, x, y, z, v; 36 37 while (scanf("%d%d", &n, &m) != EOF) { 38 rep(i, n) h[i] = 1, f[i] = -1; 39 t = c = ans = 0; 40 while (m--) { 41 scanf(" %s", opr); 42 if (*opr == 'K') 43 scanf("%d", &v), c = c * ans + v, ans = 0; 44 else { 45 scanf("%d%d", &x, &y); 46 x = (c * ans + x) % n; 47 y = (c * ans + y) % n; 48 49 if (*opr == 'R') { 50 merge(x, y, ++t); 51 } else { 52 scanf("%d", &z); 53 z = (c * ans + z) % n; 54 ans = ((get(x, t) == get(y, t)) == (get(x, t - z) == get(y, t - z))); 55 printf("%c ", ans ? 'N' : 'Y'); 56 } 57 } 58 } 59 } 60 61 return 0; 62 }