Event summary
Topic aspect
 I have strictly controlled the whole problem setting of this competition. After the ABA problem setting group, the ABC problem setting group's first battle
 One obvious aspect is that the title has become more beautiful (alphanumeric and subscript are all used) l a t e x latex latex, code blocks are all in the form of backquotes)
 The title style is closer to the ladder style
 The quality of the topic is also high. I cut off all idea s that are not in line with the style of the ladder
 After three tests, the correctness is guaranteed
Problem group
A B A & A B ABA\&AB The ABA & AB team retired, A B C ABC Upper level of ABC problem group
Team leader: Bei
Team members: Xun, Jie, Chi, Ju
Difficulty control
 By beautifying the problem surface, repeatedly improving and modifying the meaning of the problem to facilitate everyone's understanding, and giving tips, we can continuously reduce the difficulty and achieve an appropriate difficulty
 It was found that there were still yards in the whole game, so the 4h game time was given
 L23 tested the examiners, and the three examiners couldn't Therefore, a prompt is given: convert multisource and multi sink points to single source and single sink points
 L31 gives the hint of complete binary tree, because a toplevel full score test question taker of PTA who does not want to be named has forgotten the definition of complete binary tree, and it is unexpected that many people must have confused the definitions of complete binary tree and perfect binary tree
 L33 was originally a 5point delivery proposition that can only be written for 70 minutes at the first level of school selection. I replaced it with a topic that is easy to cheat points and may be able to be done by someone
Degree of simulation
 It can be said that it is the closest school selection to the official competition, whether it is topic style, topic difficulty or competition mode
 In the mode, you can only view your own submission records (you can't see whether others submit WA or MLE), but you can see the ranking and the specific scores of other players (you can see the list in the official competition, and you can refer to the answers of your teammates)
L1 basic level
L11 most delicious
Author: Bei
Algorithm idea
 It continues the guessing style of the first question in JMU's school selection over the years. In previous years, this sub question was given in English and there was escape source code. This time, it was given in Chinese
 There are two kinds of people. The one who knows the best food is mine. It will pass in 10 seconds
 If you don't know, follow the last Hint of Hint and follow the steps said by Hint. It's too late to write a code
 I have been controlling the difficulty and direction of the whole problem group. I hope you can still get more points and the degree of distinction will be more obvious.
code implementation
#include <bits/stdc++.h> using namespace std; int main() { string L="GNINIEBNIL"; for(int i = 0 ; i < L.size() ;i ++) { L[i]= L[i]  'A' + 'a'; } reverse(L.begin(),L.end()) ; cout << L <<" shi JMU zui cai de ren."; }
L12 repeater
Author: Bei
thinking
 Send sub questions properly. There's nothing to say
code implementation
#include <bits/stdc++.h> using namespace std; #define el '\n' #define rep(i, a, b) for (int i = (a); i <= (b); i++) int main() { cin.tie(0); cout.tie(0); rep(i, 1, 5) cout << "beibei shi Jimei University zui cai de ren" << el; }
L13 JMU Cangjie reproduction  what type of Chinese characters of Jue Jue Zi
Author: Xun
meaning of the title
The last sentence is the key, that is, output n lines ""
Problem solving ideas
Output n lines'  '
Chinese Chinese characters make complaints about the "add, subtract, multiply and divide" of the Chinese characters, but not half the dash.
It's really the father who dug his son's grave  digging his son
code
#include<bits/stdc++.h> using namespace std; int main() { int n; cin >> n; for (int i = 0; i < n; i++) { if (i)cout << endl; cout << "—"; } }
L14
Author: Jie
Algorithm idea
The exchanged bottles can also be exchanged repeatedly, and the circular structure can simulate the exchange process until they can no longer be exchanged
code implementation
#include<bits/stdc++.h> using namespace std; int n, k, m; int main() { cin >> n >> k; int ans = 0; do { ans += n; m += n; //Get n caps n = m / k; m %= k; }while(n); cout << ans; }
L15 reverse repeater
Author: Bei
Topic report
 I'm afraid someone has been stuck in the blank space at the end of the line and so on. I'm still doing the problem. Finally, I specially reminded
 I set up six test points
 Test point 0, basically correct, small data, 3 points
 Test point 1, one sentence only, 1 point
 Test point 2, three sentences are the same, 1 point
 Test point 3, two sentences, 1 point
 Test point 4, big data n = 1 e 5 n=1e5 n=1e5, speech length is 100 characters, 8 points
 Test point 5, big data n = 1 e 5 n=1e5 n=1e5, if all speeches are the same, 1 point
Algorithm idea
 We output the previous sentence until we encounter different speeches
 Then let's open a cnt to count how many times the previous sentence appeared, and then consider whether he needs to redo it
 But in this way, we must have one more time left in the end, so we can output it once in the end
code implementation
#pragma GCC optimize("O3") #include <bits/stdc++.h> #include <unordered_map> #include <unordered_set> using namespace std; #define debug(x) cerr << #x << ": " << x << '\n' #define bd cerr << "" << el #define el '\n' #define cl putchar('\n') #define pb push_back #define eb emplace_back #define x first #define y second #define rep(i, a, b) for (int i = (a); i <= (b); i++) #define loop(i, a, b) for (int i = (a); i < (b); i++) #define dwn(i, a, b) for (int i = (a); i >= (b); i) #define ceil(a, b) (a + (b  1)) / b #define ms(a, x) memset(a, x, sizeof(a)) #define inf 0x3f3f3f3f #define db double typedef long long LL; typedef long double LD; typedef pair<int, int> PII; typedef pair<db, db> PDD; typedef vector<int> vci; typedef map<int, int> mii; typedef mii::iterator mii_it; const int N = 1e5 + 10, M = 2e6 + 10, E = 1e3 + 10, md = 1e9 + 7; const double PI = acos(1), eps = 1e8; int T, n, m, cnt; string last, now; void out() { if (cnt < 3) { rep(i, 1, cnt) { cout << last << el; } } else cout << last << el; return ; } int main() { // freopen("2.in", "r", stdin); // freopen("2.out", "w", stdout); cin.tie(0); cout.tie(0); cin >> n; getchar(); rep(i, 1, n) { getline(cin, now); if (now != last) { if(cnt) out(); cnt = 1; last = now; } else { cnt++; } } out(); }
L16 different strings
Author: Chi
Topic statement
General idea: give n strings for each group of test data, and ask how many different strings there are in total, which is not case sensitive
Problem solving ideas

Read the whole line into the string first. Because there are spaces in the string, you can't directly read cin and scanf. It is recommended to read the whole line with getline(cin,s)

Traverses the entire string, changing lowercase letters to uppercase and unifying the case of letters. Do not remove spaces, because AA and AA are two different strings.

The first method is to use set, directly store the string in set, and finally output the number in set (set has the function of automatic de duplication).
If you can't use set, you can build a string array and compare each newly entered string with each bit in the array. If it's different, put the new string into the array, and then add 1 to the number of different strings.
code implementation
//Method 1: use set #include<bits/stdc++.h> using namespace std; #define ll long long typedef pair<int, int> PLL; #define inf 0x3f3f3f3f int main(){ int t; cin>>t; while(t){ int n; cin>>n; getchar(); set<string>s; for(int i=0;i<n;i++){ string a; getline(cin,a); int len=a.length(); for(int j=0;j<len;j++){ if(a[j]>='a'&&a[j]<='z')a[j]=a[j]'a'+'A'; } s.insert(a); } cout<<s.size()<<endl; } }
//Method 2: #include<bits/stdc++.h> using namespace std; #define ll long long typedef pair<int, int> PLL; #define inf 0x3f3f3f3f string a[1100]; int tot = 0; int main() { int t; cin >> t; while (t) { int n; cin >> n; getchar(); int cnt = 0; for (int k = 0; k < n; k++) { string s; getline(cin, s); int len = s.length(); for (int j = 0; j < len; j++) { if (s[j] >= 'a' && s[j] <= 'z')s[j] = s[j]  'a' + 'A'; } int i; for (i = 0; i < cnt; i++) { int len2 = a[i].length(); if (len2 != len)continue; int j; for (j = 0; j < len; j++) { if (a[i][j] != s[j])break; } if (j == len)break; } if (i == cnt)a[cnt++] = s; } cout << cnt << endl; } }
L17 FJCCGPLT
Author: Xun
Topic statement
Given the scores of 10 people from n teams, simulate according to the rules of the ladder competition, calculate the scores of each team and sort them.
Problem solving ideas
 Read the team name according to the line input
 For each team, input the scores of 10 people and 15 questions to process the scores of L1, L2 and L3 of the team
 Judge whether the l1 score is 800 points, add the l2 score if it is enough, and add the l3 score if the l1 score is 800 points and the l2 score is 400 points. Pay attention to whether the l3 score is valid and meet the l2 score first, so as to prevent the l2 score from being 400 points, but its score is invalid.
 Finally, sort the second keyword according to the team score as the first keyword and the team name dictionary order, and then output it.
code implementation
#include<bits/stdc++.h> #include<bits/stdc++.h> using namespace std; map<string, int> m; vector<pair<int, string>> p; int main() { int n; cin >> n; getchar(); for (int i = 0; i < n; i++) { string s; getline(cin, s); int l1 = 0, l2 = 0, l3 = 0; for (int l = 0; l < 10; l++) { int g; for (int j = 0; j < 15; j++) { cin >> g; if (j < 8)l1 += g; else if (j < 12)l2 += g; else l3 += g; } } int res = l1; if (l1 >= 800)res += l2; if (l1>=800&&l2 >= 400)res += l3; getchar(); p.push_back(make_pair(res, s)); } sort(p.begin(), p.end()); for (auto k : p) { cout << k.second << ' ' << k.first << endl; } }
L18 "who's lying"
Author: Bei
Topic report

Originally, I wanted to lose the accuracy of double and directly compare the total long long. The accuracy must be higher than the average value. After thinking about it, I still didn't deliberately card it

I set four test points for this question

No one really uses "LBN" and "LBN" a 0 a_0 a0} corresponding string?

Test point 1, basically correct, 4 points

Test point 2, maximum data, all correct, open long long, 10 points

Test point 3 is basically correct, but it will be stuck by "LBN" and "LBN", 5 points

Test point 4, test nobody, 1 point

because 1 0 5 × 1 0 5 = 1 0 10 10^5 \times 10^5 =10^{10} one hundred and five × 105 = 1010, so you need to turn on LL
Algorithm idea
 It's easy to use a map. Just record the values of two maps. The map has its own sorting. Remember to turn on LL for seconds
 It's OK to write your own hash. A string can be up to 5 digits in length, and you can regard it as hexadecimal
code implementation
#pragma GCC optimize("O3") #include <bits/stdc++.h> #include <unordered_map> #include <unordered_set> using namespace std; #define debug(x) cerr << #x << ": " << x << '\n' #define bd cerr << "" << el #define el '\n' #define cl putchar('\n') #define pb push_back #define eb emplace_back #define x first #define y second #define rep(i, a, b) for (int i = (a); i <= (b); i++) #define loop(i, a, b) for (int i = (a); i < (b); i++) #define dwn(i, a, b) for (int i = (a); i >= (b); i) #define ceil(a, b) (a + (b  1)) / b #define ms(a, x) memset(a, x, sizeof(a)) #define inf 0x3f3f3f3f #define db double typedef long long LL; typedef long double LD; typedef pair<int, int> PII; typedef pair<db, db> PDD; typedef vector<int> vci; typedef map<int, int> mii; typedef mii::iterator mii_it; const int N = 110, M = 2e6 + 10, E = 1e3 + 10, md = 1e9 + 7; const double PI = acos(1), eps = 1e8; int T, n, m; map<string , LL> last, now; string name[N]; string b = "1", s;//Because S is composed of letters, using a numeric string to represent Beibei can avoid hash conflict //State design in hash LL x; int main() { // freopen("2.in", "r", stdin); // freopen("2.out", "w", stdout); cin.tie(0); cout.tie(0); cin >> n >> m; rep(i, 1, m) { cin >> x; last[b] += x; } rep(i, 1, n) { cin >> s; name[i] = s; rep(i, 1, m) { cin >> x; last[s] += x; } debug(last[s]); } cin >> now[b]; int cnt = 0; rep(i, 1, n) cin >> now[name[i]]; for (auto it : last) { if(it.y >= last[b] && now[it.x] < now[b]) {//The historical average is higher than Beibei, and the score is lower than Beibei cnt ++ ; cout << it.x << el; } } if(!cnt) { cout << "Yeah! Nobody!" <<el; } }
L2 progressive class
L21 tree height
Author: Ju
meaning of the title
To build a tree, find the height of the tree (the number of layers of the tree)
Problem solving ideas
After building the tree according to the meaning of the topic, dfs just click.
code
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; vector<int> G[maxn]; int ans = 0; // The root node depth is 1 void dfs(int cur, int deep) { ans = max(ans, deep); for (auto& val : G[cur]) { dfs(val, deep + 1); } } // I starts from 0, and a[i] represents the father number of i+1 int main() { ios::sync_with_stdio(false); int n; cin >> n; int i; int num; for (i = 1; i < n; i++) { cin >> num; G[num].push_back(i); } dfs(0, 1); cout << ans << endl; return 0; }
L22 ACM membrane culture
Author: Bei
Topic report
To investigate the application of set and string, I set seven test points
 Test point 0. With alias, basically correct, 5 points
 Test point 1. Case sensitive alias, small data, 1 point
 Test point 2. Case sensitive alias, small data, 1 point
 Test point 3. No alias, basically correct, 4 points
 Test point 4. n is the largest, the line length is the longest, and the character is the longest. It has alias case, 9 points
 Test point 5. Shen should be judged as Normal according to the meaning of the question, the case of card Shen, and the case of Shen and Shen. This person did not appear in the worship behavior, but it was judged as Dalao. Only those who appeared were recorded and will be stuck, 3 points
 Test point 6. For example, if JieShen's subsequent record is Jie, he will be stuck, 2 points
Algorithm idea
 In fact, the four string grading is a cover. You only need numbers to represent the grade
 When you encounter this kind of simulation problem, as long as you think carefully, you can save a lot of detours. If you hit it directly, it's easy to hit more and more bug s
 In fact, this question is not difficult. Originally, the question I planned to give also included that everyone has multiple aliases, and the level level will change according to the aliases
 Considering the difficulty of the whole copy, I'm afraid it's too difficult, so I'll reduce it to the final version
 The four sets < string > maintain the alias pool, representing the level, which has little to do with his original name
 First use the find function of string to find the space, substr divides this sentence into subject predicate table, and then use the find and substr functions of string to find the keyword
code implementation
#pragma GCC optimize("O3") #include <bits/stdc++.h> #include <unordered_map> #include <unordered_set> using namespace std; #define debug(x) cerr << #x << ": " << x << '\n' #define bd cerr << "" << el #define el '\n' #define cl putchar('\n') #define pb push_back #define eb emplace_back #define x first #define y second #define rep(i, a, b) for (int i = (a); i <= (b); i++) #define loop(i, a, b) for (int i = (a); i < (b); i++) #define dwn(i, a, b) for (int i = (a); i >= (b); i) #define ceil(a, b) (a + (b  1)) / b #define ms(a, x) memset(a, x, sizeof(a)) #define inf 0x3f3f3f3f #define db double typedef long long LL; typedef long double LD; typedef pair<int, int> PII; typedef pair<db, db> PDD; typedef vector<int> vci; typedef map<int, int> mii; typedef mii::iterator mii_it; const int N = 1e5 + 10, M = 2e6 + 10, E = 1e3 + 10, md = 1e9 + 7; const double PI = acos(1), eps = 1e8; int T, n, m; string name, line, sub, ver, pred; int level1, level2, first_blank, second_blank; char c; set<string> L[5]; int get_level(string &s) { if (s == "ZhanShen") return 4; else if (s == "BeiShen") return 1; else if (s.size() > 4 && s.substr(s.size()  4, 4) == "Shen") return 3; else { for(int i = 1; i <= 4; i ++ ) { if(L[i].find(s) != L[i].end())//Look in the alias pool { return i; } } return 2; } } int main() { cin.tie(0); cout.tie(0); cin >> n; getchar(); while (n) { cin >> name >> c; getchar(); getline(cin, line); cout << name << " : " << line << el; first_blank = line.find(' '); sub = line.substr(0, first_blank);//subject second_blank = line.find(' ', first_blank + 1); ver = line.substr(first_blank + 1, second_blank  first_blank  1);//predicate pred = line.substr(second_blank + 1, line.size()  1  second_blank);//Predicative cout <<"Translate : "; if (pred.find("lowlevel") != pred.npos  pred.find("stupid") != pred.npos  pred.find("fool") != pred.npos  pred.find("caigou") != pred.npos) { level1 = get_level(name); cout << name; switch(level1) { case 1:{ cout << " is ZiCaoing now." << el; break; } case 2:{ cout << " is MaiRuoing now." << el; break; } case 3: case 4:{ cout << " is ZhuangCaiing now." << el; break; } } if(sub != name && sub != "I") L[level1].insert(sub); } else if (pred.find("highlevel") != pred.npos  pred.find("clever") != pred.npos  pred.find("genuis") != pred.npos  pred.find("talent") != pred.npos) { level1 = get_level(name); level2 = get_level(sub); cout << name; if (level1 < level2) { cout << " is truly worshipping now." << el; } else { cout << " worships for taking care of other people's feelings." <<el; } } else cout <<"sto "<< name << " orz." <<el; } }
L23 the dishes are home
Author: Bei
Topic report
summary
 This topic is a multisource and multi sink shortest path problem. The essence is to investigate the single source and single sink shortest path problem
 The problem is still the shortest path. You only need to add two points on the template  super source point + Super sink point
 I also have roughly three grades:
 First gear: each time, directly select the fresh supermarket or deposit point as the starting point, and then run the shortest circuit for many times. The score is expected 10 − 16 branch 1016 points 10 − 16 points. The two best cases are passing test points 1,2,5,6 (p is the starting point, 14 points) or test points 1,2,3,4,6 (q is the starting point, 16 points)
 Second gear: select the small and mediumsized P and Q as the starting point, and it is estimated that 18 − 19 1819 18 − 19 points, passing the first five test points
 The third level, positive solution super source point + Super sink point, is expected to score 25 points, passing all test points.
Data analysis
 I set up seven test points
 Test point 1: n = 100 , m = 200 , p = q = 10 n=100,m=200,p=q=10 n=100,m=200,p=q=10, test basic correctness, 3 points
 Test point 2: n = 100 , m = 200 , p = q = 10 n=100,m=200,p=q=10 n=100,m=200,p=q=10, test the basic correctness, 3 points. These two test points can run multiple times, and the shortest path of single source must pass
 Test point 3: n = 1 e 5 , m = 2 e 5 , p = 5 e 4 , q = 10 n=1e5,m=2e5,p=5e4,q=10 n=1e5,m=2e5,p=5e4,q=10, 3 points
 Test point 4: n = 1 e 5 , m = 2 e 5 , p = 99990 , q = 10 n=1e5,m=2e5,p=99990,q=10 n=1e5,m=2e5,p=99990,q=10, only fresh supermarket and deposit point are tested, 1 point
 Test point 5: n = 1 e 5 , m = 2 e 5 , p = 10 , q = 5 e 4 n=1e5,m=2e5,p=10,q=5e4 n=1e5,m=2e5,p=10,q=5e4, 4 points
 Test point 6: test that all fresh food supermarkets and deposit points are not connected, 1 point
 Test point 7: n = 1 e 5 , m = 2 e 5 , p = 80 , q = 80 , w i ∈ [ 5 e 3 , 1 e 4 ] n=1e5,m=2e5,p=80,q=80,w_i \in[5e3,1e4] n=1e5,m=2e5,p=80,q=80,wi ∈ [5e3,1e4], 10 points
Algorithm idea promotion
Algorithm 1: violence + shortest path
 In the shortest path problem, the starting point and ending point can undoubtedly be changed
 An obviously violent idea, take each fresh supermarket as the starting point and run the shortest path once
 Then, in each shortest path, select the shortest distance to the deposit location and set it as the shortest distance of the current time
 So run a total of p p The answer can be obtained by the shortest path p times
 My code here is S P F A SPFA SPFA, of course D i j k s t r a Dijkstra Dijkstra writing is the same (after all, it is timeout)
Complexity analysis
 Time complexity. For the shortest path, the average case of the shortest path of SPFA is O ( k ∣ E ∣ ) O(kE) O(k∣E∣), k k k is a constant, but if the questioner deliberately cards you, it may be achieved O ( ∣ V ∣ ∣ E ∣ ) O(VE) O(∣ V ∣ E ∣) (this is rare) if Dijkstra heap is used to optimize, the complexity is stable O ( V log E ) O(V \log E) O (vloge), Dijk heap optimization is recommended for ACM competition. The figure is O ( ∣ E ∣ ) O(E) O(∣ E ∣), scan the end point again after each SPFA run, which is O ( q ) O(q) O(q), the shortest circuit needs to run p p p times, the total time complexity is O ( p ( k ∣ E ∣ + q ) ) O(p(kE+q)) O(p(k∣E∣+q))
 Space complexity, defining a queue, dis,vis array, as O ( V ) O(V) O(V)
Algorithm 2: super source sink + shortest path
 In the above process, we will find that our S P F A SPFA During SPFA, many repeated paths will be run
 Doing these processes repeatedly not only takes time, but also space
 So what can we do to eliminate these processes? How to optimize has become the focus of this topic
 Let's assume that the graph is like this
 Green represents the fresh supermarket, red represents the deposit office, and black represents other places
 Here I'll first talk about a practice, and then explain why
 Suppose that all fresh supermarkets are the same wholesaler, is it not too much for us to install a "wormhole conveyor" between fresh supermarkets and fresh supermarkets?
 That is, edges with a cost of 0 can be established between two green nodes, and between two red nodes
 Why can this be done?
 To the contrary, if this is the shortest path we finally seek, then there are only black nodes on this path except for the starting point and the ending point
 As shown in the figure below, assuming that our answer is (1 – > 3), it is obvious that starting from 2 will be better
 That is, if there are non black nodes on the original path, the original shortest path must be replaced by a shorter path
 After the new graph is established, if the source point initially selected does not run the shortest path of the answer, we can spend "0" (unconditionally transfer to other green nodes) to run the new answer, so as to omit the repeated process of finding the shortest path
 In this way, we only need to build two edges (complete subgraph) in the same non black node, and finally run the shortest path once to calculate the answer
Re optimization
 We will find that we only need to ensure the connectivity between non black nodes of the same color and the same color, so we don't need to establish a complete subgraph, we just need to establish a tree, so the time to establish edges can be much less
Scheme I
 From the first node in P to each node after P, an edge with a weight of 0 is established, that is, "chrysanthemum graph"
Scheme II
 The two adjacent sides before and after the subscript in P establish a connecting edge with a weight of 0, that is, "linked list"“
Programme III

Define a super source point with the number of 0 (not used in the figure), and establish its edge connection with each number weight of 0 in P

Here we choose scheme 3. The above two are also feasible, but scheme 3 is easier to write and the amount of code is smaller

(the same is true for the implementation of red node Q)
Complexity analysis
 Time complexity. For the shortest path, the average case of the shortest path of SPFA is O ( k ∣ E ∣ ) O(kE) O(k∣E∣), k k k is a constant. Construction drawing is O ( ∣ E ∣ ) O(E) O(∣ E ∣), the connecting edge of the super source point and sink point is O ( p + q ) O(p+q) O(p+q), the total time complexity is O ( k ∣ E ∣ + p + q ) O(kE+p+q) O(k∣E∣+p+q)
 Space complexity, defining a queue, dis,vis array, as O ( V ) O(V) O(V)
code implementation
#pragma GCC optimize("O3") #include <bits/stdc++.h> #include <unordered_map> #include <unordered_set> using namespace std; #define debug(x) cerr << #x << ": " << x << '\n' #define bd cerr << "" << el #define el '\n' #define cl putchar('\n') #define pb push_back #define eb emplace_back #define x first #define y second #define rep(i, a, b) for (int i = (a); i <= (b); i++) #define loop(i, a, b) for (int i = (a); i < (b); i++) #define dwn(i, a, b) for (int i = (a); i >= (b); i) #define ceil(a, b) (a + (b  1)) / b #define ms(a, x) memset(a, x, sizeof(a)) #define inf 0x3f3f3f3f #define db double typedef long long LL; typedef long double LD; typedef pair<int, int> PII; typedef pair<db, db> PDD; typedef vector<int> vci; typedef map<int, int> mii; typedef mii::iterator mii_it; const int N = 1e5 + 10, M = 2e6 + 10, E = 1e3 + 10, md = 1e9 + 7; const double PI = acos(1), eps = 1e8; int T, n, m, p, q; int x, y; vector<PII> v[N]; int SPFA() { queue<int> q; q.push(0); //Put in starting point bool vis[N]; //Tag, whether in queue int dis[N]; //Distance to starting point memset(dis, 0x3f, sizeof dis); //Initialization is infinite memset(vis, 0, sizeof vis); //The initial is not in the queue vis[0] = 1; //The starting point has joined the team dis[0] = 0; //The distance from the super source point to itself is 0 while (!q.empty()) { int u = q.front(); q.pop(); for (auto it : v[u]) { //Accessing u's neighbors through the adjacency table if (dis[u] + it.y < dis[it.x]) { //If you can relax the edges dis[it.x] = dis[u] + it.y; if (!vis[it.x]) { //If it is not in the queue, it is put in the queue vis[it.x] = 1; q.push(it.x); } } } } if (dis[n + 1] == dis[n + 2]) return 1; //If the graph is not connected return dis[n + 1]; } int main() { // freopen("6.in","r",stdin); // freopen("6.out","w",stdout); cin.tie(0); cout.tie(0); cin >> n >> m >> p >> q; int u; rep(i, 1, p) { cin >> u; v[u].pb({0, 0}); v[0].pb({u, 0}); } rep(i, 1, q) { cin >> u; v[u].pb({n + 1, 0}); v[n + 1].pb({u, 0}); } int a, b, c; rep(i, 1, m) { cin >> a >> b >> c; v[a].pb({b, c}); v[b].pb({a, c}); } cout << SPFA() << el; }
L24 you just got home
Author: Xun
Topic statement
Concise and comprehensive, give an undirected graph and find the minimum dictionary order M S T MST MST (minimum spanning tree)
Problem solving ideas
 Thinking about classics M S T MST Greedy algorithm of MST—— K r u s k a l Kruskal Kruskal, after sorting by edge weight, select the edge with the smallest weight and will not form a ring
 For edges with different weights, only the smaller one can ensure the minimum spanning tree, without considering the name of the edge. For several edges with the same weight, if there is a "conflict", that is, these edges can only select some of them, then obviously we need to select the edges with the smallest edge name list
 Therefore, when sorting edges, the edge weight is the first keyword, and the edge name dictionary order is the second keyword k r u s k a l kruskal kruskal algorithm is used to select edges, and finally judge whether there is a spanning tree.
 As for why each selection of the side with the smallest name dictionary order can minimize the dictionary order of the last sorted and spliced string, readers can prove it by themselves and refer to scheme a and b s o r t ( a ) ≤ s o r t ( b ) sort(a)≤sort(b) sort(a)≤sort(b)， c ≤ d c≤d c ≤ d is not hard to get s o r t ( a + c ) ≤ s o r t ( b + d ) sort(a+c)≤sort(b+d) sort(a+c) ≤ sort(b+d), note s o r t ( ) sort() sort() is the operation of splicing after sorting the edge names in the group in the meaning of the question. Therefore, this method can gradually construct a dictionary with the smallest order M S T MST MST
code implementation
#include<map> #include<stdio.h> #include<iostream> #include<vector> #include<string> #include<math.h> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define ll long long struct edge { string name; int u, v,cost; }e[200005]; int fa[100005]; int find(int r) { return fa[r] == r ? r : fa[r] = find(fa[r]); } void join(int x, int y) { int fx = find(x), fy = find(y); fa[x] = fy; } bool cmp(edge a, edge b) { return a.cost < b.cost  (a.cost == b.cost&&a.name < b.name); } vector<string> ans; int main() { int n, m; cin >> n >> m; for (int i = 1 ;i <= n; i++) { fa[i] = i; } for (int i = 0; i < m; i++) { cin >> e[i].name; cin >> e[i].cost; cin >> e[i].u; cin >> e[i].v; } sort(e, e + m, cmp); for (int i = 0; i < m; i++) { int u = e[i].u, v = e[i].v; if (find(u) != find(v)) { ans.push_back(e[i].name); join(u, v); } } int c = 0; sort(ans.begin(), ans.end()); for (int i = 1; i <= n; i++) { if (find(i) == i)c++; } if(c==1)for (auto p : ans)cout << p; else cout << "don't cout or printf me directly!!!!!!!\\Orz/"; }
L3 top
Is L31 a legal heap
Author: Bei
Topic report
summary
 People think this question is an excellent one. The extremely strong ladder style combines the data structure in the class, and it is also difficult
 At that time, there were five people in the problem group. Apart from me, there were three other people to test the problem. Jie god was A in 40 minutes. Xun and Chi God struggled for A long time, and finally they were A.
 At first, Mr. Xun gave a wrong practice without technical content, and then got more than 20 points
 I just remembered that I was in a bad state that day when I worked out the data. I did it casually. Except for this problem, I didn't write out the problem analysis, I wrote all the other problems, so I resolutely recreated a stronger and more comprehensive data
 After all, now that the ABC question group is in power, there can be no mistakes like the previous ABA question group and AB question group (dog head saves life)
 So later, I spent another whole night writing six data generation codes and creating an extremely comprehensive data.
 Good trials are inseparable from excellent topics and data.
Data analysis

I made four data for this problem, and each data has T = 10 T=10 T=10, which is designed to prevent pure YES and NO from cheating points

Test point 1, small data n ∈ [ 100 , 200 ] n \in [100,200] n ∈ [100200], test the basic correct properties of the algorithm. For the implementation of this problem, even if each point is soaked once as the root node, 10 points

The above is the code I used to generate the data of the test point, which is composed of 10 small data. Small represents this small data point, and others can understand it by themselves according to the English meaning

Test point 2, big data, for some n ∈ [ 2 15 + 2 7 , 2 16 − 2 7 ] n \in [2^{15}+2^7,2^{16}2^7] n ∈ [215 + 27216 − 27], another part n ∈ [ 5 e 4 , 1 e 5 ] n \in [5e4,1e5] n ∈ [5e4,1e5], the general direction of the algorithm is basically correct, 9 points

Test point 3, big data, for some n ∈ [ 2 15 + 2 7 , 2 16 − 2 7 ] n \in [2^{15}+2^7,2^{16}2^7] n ∈ [215 + 27216 − 27], another part n ∈ [ 5 e 4 , 1 e 5 ] n \in [5e4,1e5] n ∈ [5e4,1e5], if one group contains a chain, if the first step is direct recursive search, the stack will overflow because the number of recursive layers is too deep (100000 layers), and RE (segment error) will be reported, 9 points

President Xun and I tested the above paragraph errors together, because the original second test point also contained chains, so I finally deleted the chains in the second test point

The questioner believes that if the general direction is not wrong, he can also get 21 points, so as not to be stuck by this chain, which is more differentiated

Test point 4, boundary test, n ≤ 2 n \leq 2 If n ≤ 2, 2 points

Careful mind can get full
Difficulty analysis
 When the examiners checked the questions, they found that there was indeed some difficulty. Our problem group worked so hard, let alone other students
 So I planned to reduce the difficulty and improve the scoring rate according to the time and reaction of the tester, so I gave an explanation of the complete binary tree and a hint about the problem solution in hint
 Because it is found that four people in the problem group have made this problem, but they use three different methods, but they all use the same thing, so I give the most key tips.
 A variety of solutions have also become a feature of this problem.
 Overall, this problem is still very difficult.
 In order to improve the scoring rate, I specially changed the time limit of 600ms to 1500ms. I'm afraid someone will get stuck because cin or scanf is not fast enough. As long as the algorithm is basically correct.
Algorithm 1: pruning + heap properties + map statistics
Author: Bei
Algorithm idea
 After reading the topic at first glance, because the tree can rotate, the first reaction is generally to find all the minimum values, and then find all the maximum values, and then judge based on them. Later, it is found that there may be multiple maximum and minimum values, and construct a set of data with 5k maximum and 5k minimum values. This wrong algorithm can be stuck. Later, according to the nature of the heap, The node with edge 2 can be the root, which optimizes the algorithm
 Next, we only need to take the node with degree 2 as the root to judge whether it is a legal heap. Because of the complexity problem, the complexity of judging whether it is a large and small root heap is significantly less than that of judging whether it is a perfect binary tree, so we first judge whether it is a large and small root heap
 It's easy to judge the size of the root pile. I won't say it here
 To judge whether it is a perfect binary tree, a set of data can be constructed, as follows
1
12
1 2 3 4 5 6 7 8 9 10 11 12
1 2
1 3
2 4
2 5
3 6
3 7
4 8
4 9
6 10
7 11
7 12
 Therefore, if we only judge the bottom layer, and the left and right nodes of the tree can be interchanged, it is obviously a wrong idea. Therefore, we need to judge not only the bottom layer, but also all layers
 First, judge whether the number of nodes in all layers is legal. Here, the root node is layer 0, and num[i] represents the number of nodes in layer I. If num[i]= (1 < < I) is illegal
 num_leaf[i] stands for i i The number of leaf nodes contained in the subtree of node i
 Maintain 18 large top piles (subscript to 17)( 2 16 ≤ 2^{16}\leq 216 ≤ n Max ≤ 2 17 \leq 2^{17} ≤217)
 Let x = 1 < < (DI), nsum represents the number of leaf nodes of the whole tree, and one layer is represented by a heap for nodes i i I put num_leaf[i] in the h [ i ] h[i] h[i] heaps, where h [ i ] h[i] h[i] stands for the third party i i What layer are i nodes on
 Theoretically, the same layer should have only several x values and at most one nonx value (i.e. nsum%x)
 It can be understood that the number of leaf nodes is taken as a tag number X. if it is a legal perfect binary tree, for each layer, there is only one nonx value at most
 We can judge whether it is a perfect binary tree with the help of 18 large top heaps or 18 maps (because there are only 2 values at most in the same layer)
 As for how to judge the method of large top heap, if top()=x, pop directly. Otherwise, there is only one case, that is, top()=nsum%x and heap.size()==1
 The two values stored in the map here are much faster than those here, and they are easy to write. I won't repeat them here, as above.
code implementation
#include <bits/stdc++.h> #include <unordered_map> #include <unordered_set> using namespace std; #define el '\n' #define eb push_back typedef vector<int> vci; const int N = 1e5 + 10; int T, n, m, x, y, k, a[N], num[N], h[N], num_leaf[N], d; vci v[N], rt, mx_id, mi_id; //rt stores the number of nodes with more than 2 edges bool flag = 0, vis[N]; bool check_mi(int u, int fa) { //Determine whether it is a small root pile for (int i = 0; i < v[u].size(); i++) { int t = v[u][i]; if (t == fa) continue; if (a[t] < a[u]) return 0; if (!check_mi(t, u)) return 0; } return 1; } bool check_mx(int u, int fa) { //Determine whether it is a large root heap for (int i = 0; i < v[u].size(); i++) { int t = v[u][i]; if (t == fa) continue; if (a[t] > a[u]) return 0; if (!check_mx(t, u)) return 0; } return 1; } bool check_num() { for (int i = 1; i <= n; i++) { if (v[i].size() > 3) return 0; //More than three sides must not be the root of a binary tree if (v[i].size() == 2) { rt.eb(i); } } if (rt.size() > 2) return 0; //There are at most two sz==2 in a heap return 1; } void get_leaf(int u) { //Gets the number of leaf nodes in layer d (the lowest layer) in the tree with the current node as the root num_leaf[u] = 0; //Multiple groups of samples, initial value if (h[u] == d) { //Leaf node num_leaf[u] = 1; return; } for (int i = 0; i < v[u].size(); i++) { int t = v[u][i]; if (!vis[t]) { vis[t] = 1; get_leaf(t); num_leaf[u] += num_leaf[t]; //Plus num_l[] } } } bool check_per(int u) { //Determine whether it is a perfect binary tree if (n <= 2) return 1; //Below two nodes, it must be queue<int> q; q.push(u); memset(vis, 0, sizeof vis); memset(h, 0, sizeof h); memset(num, 0, sizeof num); vis[u] = 1; h[u] = 0; num[0] = 1; while (!q.empty()) { //bfs search for node depth int t = q.front(); q.pop(); for (int i = 0; i < v[t].size(); i++) { int w = v[t][i]; if (!vis[w]) { vis[w] = 1; q.push(w); h[w] = h[t] + 1; num[h[w]]++; //Number of nodes in the current layer } } } d = log(n) / log(2); //Maximum depth for (int i = 1; i < d; i++) { if (num[i] != (1 << i)) return 0; //Layer i has (2^i) nodes } memset(vis, 0, sizeof vis); vis[u] = 1; get_leaf(u); //Gets the number of leaf nodes in layer d (the lowest layer) in the tree with the current node as the root // Priority_queue < int > heap [18]; / / the ith large top heap stores num_l [] map<int, int> mp[18]; for (int i = 1; i <= n; i++) if (num_leaf[i]) mp[h[i]][num_leaf[i]] ++ ; int nsum = n  (1 << d) + 1; //There are (1 < < d)  1 nodes in the first d1 layer. Subtract n to get the number of nodes in the last layer, i.e. num[d]..... i m sb for (int i = d  1; i >= 0; i) { x = 1 << (d  i); if(mp[i].size() > 2) { return 0; } else { for(auto it : mp[i]) { if(it.first !=x ) { if(it.second > 1  it.first != nsum % x) return 0; } } } } return 1; } void check() { //Check whether it is a legal heap for (int i = 0; i < rt.size(); i++) if (check_mi(rt[i], 0)  check_mx(rt[i], 0)) //Check whether it is a small root pile or a large root pile if (check_per(rt[i])) { //Check whether it is a perfect binary tree flag = 1; return; } } void Pr(bool f) { //Output results if (f) cout << "YES" << el; else cout << "NO" << el; } int main() { cin.tie(0), cout.tie(0), cin.sync_with_stdio(false); cin >> T; while (T) { cin >> n; rt.clear(); //initial value for (register int i = 1; i <= n; i++) v[i].clear(); //initial value for (register int i = 1; i <= n; i++) //Input weight cin >> a[i]; for (register int i = 1; i <= n  1; i++) { //Read in tree structure cin >> x >> y; v[x].eb(y), v[y].eb(x); } if (n <= 2) { Pr(1); continue; } if (!check_num()) //Check whether the number of connected edges of nodes is legal Pr(0); else { flag = 0; check(); Pr(flag); } } }
Algorithm 2: pruning + recursion + large and small root heap
Tested by: Xun
meaning of the title
Given a tree, judge whether there is at least one organization form of binary tree so that it is a large / small root heap.
Problem solving ideas
First of all, it's not hard to think of starting from the root node. We can enumerate the root nodes, but directly enumerating each point is obviously too complex (if you can't think of how to optimize, you can get a lot of points if the subsequent processing is correct) Here, we consider the nature of a heap: it is a complete binary tree. The specific definition of a complete binary tree can be Baidu by itself, but I won't repeat it here.
So we come to the first difficulty of this problem  how to prune and reduce enumeration: as a complete binary tree, there are at most two nodes whose degree is not 3 (that is, the root node and the last node of sequence traversal), otherwise, it is not a complete binary tree.
At the same time, the root node must be a node with degree 2, that is, the enumeration times of the root node is at most 2. If it is found that it is not a complete binary tree, the error can be output directly.
Therefore, in the first step, we calculate the degree of each node and record the nodes with degree 2. If we find that the number of nodes with degree 2 is not within the range of [1,2], we can directly output unsatisfied (if there are other conditions that do not meet the binary tree, for example, nodes with degree > 3 or degree = 0 can also directly output unsatisfied, so as to ensure that they are a binary tree for subsequent processing) .
Then the problem becomes: given the root node, how to judge a tree as large / small root heap.
According to the properties of large / small root heap given in the title, we can divide it into two problems:
 Is it a complete binary tree
 The weight of each node shall not be less than (≥) or greater than (≤) the value of all its child nodes.
I won't say much about the second problem. Given the root node, simply make two recursive judgments (large root heap and small root heap respectively).
Then come to the second difficulty of this problem: how to judge whether a tree is a complete binary tree. This problem itself is not difficult, but the key is that the binary tree of this problem does not explicitly limit the left and right subtrees, and only gives its two sons (or one) , the left subtree and the right subtree can be exchanged, as long as there is any way to determine the subtree so that it is a complete binary tree.
Here are the author's ideas (welcome to join your own thinking, find out your mistakes and learn together):
Recursively judge that at most one of the two children of each node can be an imperfect binary tree. If both subtrees are imperfect binary trees, it is not allowed. If only one subtree is imperfect, that subtree must be a higher subtree
Recursively judge from the root node down, constantly maintain the "number of imperfect subtrees k" (k ∈ {0,1,2}) of each node, and discuss the classification of nodes with different number of subtrees (during recursion, the parent node needs to be recorded to form a parentchild structure, otherwise it will go back)

If the node has no subtree, k is 0

If the node has only one subtree, then k is 1

The node has two subtrees. K is the sum of K of the left and right subtrees. If k=2, it is directly marked as not a heap. Otherwise, judge whether the height of the left and right subtrees is the same. If different:
 Left subtree height > right subtree height. Judge whether the k of the right subtree is 0 (that is, whether the right subtree is perfect). If it is not 0, it will be directly marked as not a heap. If it is 0, its k will be modified to 1
 The height of the right subtree > the height of the left subtree. Judge whether the k of the left subtree is 0 (that is, whether the left subtree is perfect). If it is not 0, it will be directly marked as not a heap. If it is 0, its k will be modified to 1
In short:
1. Prune and enumerate root nodes
2. Judge whether it is large / small root pile
3. Judge whether it is a perfect binary tree
code
#include<bits/stdc++.h> using namespace std; #define ll long long //Who wrote the question! Write a solution and write a few k words!!!!! //First, rule out what Beibei said typedef pair<int, int> PLL; #define inf 0x3f3f3f3f const int maxn = 100000 + 10; int a[maxn]; int vis[maxn]; int wanmei[maxn]; vector<int>g[maxn]; vector<int>root; bool check1(int u, int fa) { for (auto it : g[u]) { if (it == fa) continue; if (a[it] < a[u]) return false; if (!check1(it, u)) return false; } return true; } bool check2(int u, int fa) { for (auto it : g[u]) { if (it == fa) continue; if (a[it] > a[u]) return false; if (!check2(it, u)) return false; } return true; } bool ans = true; int check_wanmei(int root, int& f) {//0 does not have 1 more than 2 vector<int>x; for (auto it : g[root]) { if (!wanmei[it]) { x.push_back(it); wanmei[it] = 1; } } if (x.size() == 2) { int f1, f2; int dep1, dep2; dep1 = check_wanmei(x[0], f1); dep2 = check_wanmei(x[1], f2); f = f1 + f2; if (f == 2)ans = false; //if (abs(dep1  dep2) > 2)ans = false; if (dep1 == dep2); else if (dep1 < dep2) { if (f == 0)f = 1; else if (!f1)ans = false; } else if (dep1 > dep2) { if (f == 0)f = 1; else if (!f2)ans = false; } return min(dep1, dep2) + 1; } else if (x.size() == 1) { f = 1; int ff; return check_wanmei(x[0], ff); } else if (x.size() == 0) { f = 0; return 0; } return 0; } bool check_manzu(int root) { memset(vis, 0, sizeof(vis)); queue<int>q; vis[root] = 1; q.push(root); q.push(1); int flag = 0, flag2 = 0; while (q.size()) { int u = q.front(); q.pop(); if (u == 1) { if (q.size() == 0)break; if (flag  flag2)break; q.push(1); continue; } int num = 0; for (auto it : g[u]) { if (!vis[it]) { num++; q.push(it); vis[it] = 1; } } if (num == 1) { if (flag)return false; else flag++; } else if (num == 0) { flag2++; } } if (flag > 1)return false; while (q.size()) { int u = q.front(); q.pop(); int num = 0; for (auto it : g[u]) { if (!vis[it]) { num++; q.push(it); vis[it] = 1; } } if (num != 0)return false; } return true; } bool check_wanquan(int root) { memset(wanmei, 0, sizeof(wanmei)); ans = true; int f; wanmei[root] = 1; if(check_manzu(root)){ check_wanmei(root, f); return ans; } else { return false; } } bool check(int n) { if(n<=2)return true; root.clear(); for (int i = 1; i <= n; i++) { if (g[i].size() > 3) return false; if (g[i].size() == 2) root.push_back(i); } if (root.size() > 2) return false; for (auto it : root) { if (!check_wanquan(it))continue; if (check1(it, 0)  check2(it, 0))return true; } return false; } int main() { int t; cin >> t; while (t) { int n; cin >> n; for (int i = 1; i <= n; i++) { cin >> a[i]; g[i].clear(); } for (int i = 1; i < n; i++) { int u, v; cin >> u >> v; g[u].push_back(v); g[v].push_back(u); } if (check(n))cout << "YES" << endl; else cout << "NO" << endl; //if (check_wanquan(1))cout << "YES" << endl; //else cout << "NO" << endl; } }
Algorithm 3: height difference + recursion
Tested by: Jie
Algorithm idea
First determine the root: what kind of point may become the root: the point with the smallest or largest weight, and its degree can only be 2 (because the heap is a binary heap) . if the tree is a legitimate heap, there can obviously be only two points with a degree of 2. If there are more than two, the tree cannot be a binary heap. Otherwise, take these points as the roots and try to build a legitimate heap. Another special judgment of N < = 2 must be a legitimate heap
int solve() { if(n<=2)return 1; int num=0; for(int i=1; i<=n; i++) { if(vec[i].size()==2)num++; if(vec[i].size()>3)return 0; } if(num>2)return 0; for(int i=1; i<=n; i++) { if(vec[i].size()==2&&a[i]==minval) { flag=1; dfs(i,0,0);//Small root pile start if(flag==1)return 1; } if(vec[i].size()==2&&a[i]==maxval) { flag=1; dfs(i,0,1);//Big root pile start if(flag==1)return 1; } } return 0; }
The left and right subtrees cannot be dissatisfied at the same time: the following full refers to the full binary tree. For a complete binary tree, consider the root u of the complete binary tree, which needs to meet: the left subtree is a full binary tree, the right subtree is a complete binary tree, or the left subtree is a complete binary tree, and the right subtree is a full binary tree. And because the left and right subtrees of each point can be exchanged arbitrarily, it only needs to meet that at least one of the left and right subtrees of each point is a full binary tree. That is, the left and right subtrees cannot be dissatisfied at the same time.
The height difference between the left and right subtrees cannot be greater than 1: obviously, for a complete binary tree, the height of the left subtree is at most 1 higher than that of the right subtree.
How to judge a tree is a full binary tree? The left and right subtrees are full binary trees with the same height (this can ensure that the full binary tree size of the subtree is the same).
code implementation
#include<bits/stdc++.h> using namespace std; const int N=1e5+100; vector<int>vec[N]; int a[N],tag,flag,high[N],siz[N],full[N],n,minval,maxval; void dfs(int u,int fa,int key) {//key=0/1 indicates that small root heap / large root heap is being judged vector<int>son; high[u]=siz[u]=1; for(int i=0; i<vec[u].size(); i++) { int v=vec[u][i]; if(v==fa)continue; if(key==0) { if(a[v]<a[u]) { flag=0; return; } } else { if(a[v]>a[u]) { flag=0; return; } } dfs(v,u,key); siz[u]+=siz[v]; high[u]=max(high[u],high[v]+1); son.push_back(v); } if(siz[u]==1)full[u]=1;//A complete binary tree with one node else { if(full[son[0]]==1&&full[son[1]]==1&&high[son[0]]==high[son[1]])full[u]=1;//If the left and right subtrees are full and have the same height, the tree is also a complete binary tree else full[u]=0; } if(son.size()==0)return; if(son.size()==1) { if(high[son[0]]!=1)flag=0; return; } if(son.size()==2) { if(abs(high[son[0]]high[son[1]])>1){ flag=0; return; } if(full[son[0]]==0&&full[son[1]]==0) { flag=0; return; } } } int solve() { if(n<=2)return 1; int num=0; for(int i=1; i<=n; i++) { if(vec[i].size()==2)num++; if(vec[i].size()>3)return 0; } if(num>2)return 0; for(int i=1; i<=n; i++) { if(vec[i].size()==2&&a[i]==minval) { flag=1; dfs(i,0,0);//Small root pile start if(flag==1)return 1; } if(vec[i].size()==2&&a[i]==maxval) { flag=1; dfs(i,0,1);//Big root pile start if(flag==1)return 1; } } return 0; } int main() { int T,u,v; cin>>T; while(T) { cin>>n; minval=1e9; maxval=1e9; for(int i=1; i<=n; i++) { scanf("%d",&a[i]); minval=min(minval,a[i]); maxval=max(maxval,a[i]); vec[i].clear(); full[i]=0; } for(int i=1; i<n; i++) { scanf("%d%d",&u,&v); vec[u].push_back(v); vec[v].push_back(u); } if(solve())cout<<"YES"<<endl; else cout<<"NO"<<endl; } return 0; }
Algorithm 4: tree depth + recursion + size root heap
Tested by: Chi
Algorithm idea

Because it requires a complete binary tree, there are only two edges connected to the root node (in the case of only one point and two, because it must be a complete binary tree at this time). According to this property, all possible root nodes can be filtered out, and then the past can be judged one by one.

First judge whether it is a complete binary tree, and then judge whether all child nodes are greater than or less than the parent node

The form of complete binary tree is that except that the last layer is a full binary tree, and then all nodes of the last layer are on the left. We judge whether the class tree meets the condition except that the last layer is a full binary tree according to the level traversal.
When a node with only one or no child nodes in a layer is found, take the current layer as the penultimate layer and judge the nodes of the current layer and the next layer.
Because there is no provision for left and right nodes, and both sides can be changed at will, the above judgment can not determine whether all nodes in the last layer can be placed on the far left, nor whether there is only one node with only one child node. A specific judgment is needed (in fact, two judgments can be combined and written at one time, but I always write wa)
A recursive judgment records the number of only one node subordinate to the left and right child nodes, and then judges that if the number exceeds 1, it is wrong, and if the depth of the existing subtree is shallow (the subtree of only one node must extend to the last layer, so the depth is the deepest).
int check_wanmei(int root, int& f) { //0 has no only one node 1, one has only one node 2, and more than one node returns the depth vector<int>x; for (auto it : g[root]) { if (!wanmei[it]) { x.push_back(it); wanmei[it] = 1; } } if (x.size() == 2) { int f1, f2; int dep1, dep2; dep1 = check_wanmei(x[0], f1); dep2 = check_wanmei(x[1], f2); f = f1 + f2; if (f == 2)ans = false;//There are multiple nodes with only one child if (dep1 == dep2);//When the depth is the same, only the left and right subtrees of one child node can be interchanged. There is no requirement else if (dep1 < dep2) {//The depth of subtree with only one child node is required to be deeper if (f == 0)f = 1; else if (!f1)ans = false; } else if (dep1 > dep2) { if (f == 0)f = 1; else if (!f2)ans = false; } return min(dep1, dep2) + 1; } else if (x.size() == 1) { f = 1; int ff; return check_wanmei(x[0], ff);//This particular point is not depth } //Don't worry about the depth problem caused by the situation that this place has been down several times. In the previous judgment, it has been guaranteed that the last layer is a full binary tree else if (x.size() == 0) { f = 0; return 0; } return 0; }

Then judge whether the weight of each node should not be less than (≥) or greater than (≤) the values of all its child nodes.
bool check1(int u, int fa) { for (auto it : g[u]) { if (it == fa) continue; if (a[it] < a[u]) return false; if (!check1(it, u)) return false; } return true; } bool check2(int u, int fa) { for (auto it : g[u]) { if (it == fa) continue; if (a[it] > a[u]) return false; if (!check2(it, u)) return false; } return true; }
code implementation
#include<bits/stdc++.h> using namespace std; #define ll long long typedef pair<int, int> PLL; #define inf 0x3f3f3f3f const int maxn = 100000 + 10; int a[maxn]; int vis[maxn]; int wanmei[maxn]; vector<int>g[maxn]; vector<int>root; bool check1(int u, int fa) { for (auto it : g[u]) { if (it == fa) continue; if (a[it] < a[u]) return false; if (!check1(it, u)) return false; } return true; } bool check2(int u, int fa) { for (auto it : g[u]) { if (it == fa) continue; if (a[it] > a[u]) return false; if (!check2(it, u)) return false; } return true; } bool ans = true; int check_wanmei(int root, int& f) {//0 does not have 1 more than 2 vector<int>x; for (auto it : g[root]) { if (!wanmei[it]) { x.push_back(it); wanmei[it] = 1; } } if (x.size() == 2) { int f1, f2; int dep1, dep2; dep1 = check_wanmei(x[0], f1); dep2 = check_wanmei(x[1], f2); f = f1 + f2; if (f == 2)ans = false; //if (abs(dep1  dep2) > 2)ans = false; if (dep1 == dep2); else if (dep1 < dep2) { if (f == 0)f = 1; else if (!f1)ans = false; } else if (dep1 > dep2) { if (f == 0)f = 1; else if (!f2)ans = false; } return min(dep1, dep2) + 1; } else if (x.size() == 1) { f = 1; int ff; return check_wanmei(x[0], ff); } else if (x.size() == 0) { f = 0; return 0; } return 0; } bool check_manzu(int root) { memset(vis, 0, sizeof(vis)); queue<int>q; vis[root] = 1; q.push(root); q.push(1); int flag = 0, flag2 = 0; while (q.size()) { int u = q.front(); q.pop(); if (u == 1) { if (q.size() == 0)break; if (flag  flag2)break; q.push(1); continue; } int num = 0; for (auto it : g[u]) { if (!vis[it]) { num++; q.push(it); vis[it] = 1; } } if (num == 1) { if (flag)return false; else flag++; } else if (num == 0) { flag2++; } } if (flag > 1)return false; while (q.size()) { int u = q.front(); q.pop(); int num = 0; for (auto it : g[u]) { if (!vis[it]) { num++; q.push(it); vis[it] = 1; } } if (num != 0)return false; } return true; } bool check_wanquan(int root) { memset(wanmei, 0, sizeof(wanmei)); ans = true; int f; wanmei[root] = 1; if(check_manzu(root)){ check_wanmei(root, f); return ans; } else { return false; } } bool check(int n) { if(n<=2)return true; root.clear(); for (int i = 1; i <= n; i++) { if (g[i].size() > 3) return false; if (g[i].size() == 2) root.push_back(i); } if (root.size() > 2) return false; for (auto it : root) { if (!check_wanquan(it))continue; if (check1(it, 0)  check2(it, 0))return true; } return false; } int main() { int t; cin >> t; while (t) { int n; cin >> n; for (int i = 1; i <= n; i++) { cin >> a[i]; g[i].clear(); } for (int i = 1; i < n; i++) { int u, v; cin >> u >> v; g[u].push_back(v); g[v].push_back(u); } if (check(n))cout << "YES" << endl; else cout << "NO" << endl; //if (check_wanquan(1))cout << "YES" << endl; //else cout << "NO" << endl; } }
Daily work of L32 company employees
preface
To find the kth largest, it is easy to think of the weight line segment tree to find the total kth largest and the chairman tree to find the interval kth largest.
Method 1: weight segment tree + segment tree merging
Train of thought analysis
Considering that the subtree of each point is a weight line segment tree, then l o g n logn logn ＾ find the kth largest of the subtree. How to quickly find the weight line segment tree composed of the subtree of each node u? The segment trees can be merged. After merging the weight segment trees of all subtrees of u, the node information of u can be modified and added at a single point.
Realization idea
Author: Jie
 1. The data ensures that each employee has different competency values, and the competency value is < = n, then the competency values of all employees are actually an arrangement of 1n. Because the weight segment tree only records the capability value, there must be an array id to locate the capability value to the person, that is i d [ i ] id[i] id[i] indicates the number of the person whose ability value is I.
 2. How to find the kth largest interval in the weighted line segment tree? It can be split in two on the line segment tree.
 3. As for segment tree merging, it is actually a template.
code implementation
#include<bits/stdc++.h> using namespace std; const int N=1e6+10; struct edge{ int v,next; }e[N*2]; int vex[N],tot,k[N],a[N],id[N]; struct Tree{ int l,r,v; }tree[N*4]; int cnt,n,size[N],root[N],ans[N]; void add(int u,int v){ tot++; e[tot].v=v; e[tot].next=vex[u]; vex[u]=tot; } void pushup(int now){ tree[now].v=tree[tree[now].l].v+tree[tree[now].r].v; } int change(int now,int l,int r,int x,int k) { if(now==0) now=++cnt; if(l==r) { tree[now].v+=k; return now; } int mid=(l+r)/2; if(x<=mid) tree[now].l=change(tree[now].l,l,mid,x,k); else tree[now].r=change(tree[now].r,mid+1,r,x,k); pushup(now); return now; } int merge(int a,int b,int l,int r) { if(!a) return b; if(!b) return a; if(l==r) { tree[a].v+=tree[b].v; return a; } int mid=(l+r)/2; tree[a].l=merge(tree[a].l,tree[b].l,l,mid); tree[a].r=merge(tree[a].r,tree[b].r,mid+1,r); pushup(a); return a; } int query(int now,int l,int r,int k){ if(l==r)return l; int mid=(l+r)/2; if(k<=tree[tree[now].l].v)return query(tree[now].l,l,mid,k); else return query(tree[now].r,mid+1,r,ktree[tree[now].l].v); } void dfs(int u,int fa){ size[u]=1; for(int i=vex[u];i;i=e[i].next){ int v=e[i].v; if(v==fa)continue; dfs(v,u); root[u]=merge(root[u],root[v],1,n); size[u]+=size[v]; } root[u]=change(root[u],1,n,a[u],1); ans[u]=id[query(root[u],1,n,k[u])]; } int main(){ int u; cin>>n; for(int i=1;i<=n;i++){ cin>>u; add(i,u); add(u,i); } for(int i=1;i<=n;i++){ cin>>a[i]; id[a[i]]=i; } for(int i=1;i<=n;i++)cin>>k[i]; dfs(1,0); for(int i=1;i<=n;i++)cout<<ans[i]<<" "; return 0; }
Method 2: dfs order + chairman tree
Author: Jie
Train of thought analysis
conduct d f s dfs In the new sequence generated by dfs {order, the subtree of each point is an interval in the sequence. Then the problem becomes the kth largest interval of the new sequence of n queries·
Realization idea

 1. First d f s dfs dfs gets this over and over again d f s dfs dfs order
 2. With this d f s dfs Establishing chairman tree in dfs # sequence
 3. For each point in sequence, use the chairman tree to find the kth largest interval
code implementation
#include<bits/stdc++.h> using namespace std; const int N=1e6+10; struct edge{ int v,next; }e[N*2]; int vex[N],tot,k[N],a[N]; struct Tree{ int l,r,v; }tr[N*4]; int cnt,n,in[N],out[N],root[N],seg[N],id[N],top; void add(int u,int v){ tot++; e[tot].v=v; e[tot].next=vex[u]; vex[u]=tot; } void pushup(int now){ tr[now].v=tr[tr[now].l].v+tr[tr[now].r].v; } int build(int now,int l,int r){ now=++cnt; if(l==r){ tr[now].v=0; return now; } int mid=(l+r)/2; tr[now].l=build(tr[now].l,l,mid); tr[now].r=build(tr[now].r,mid+1,r); pushup(now); return now; } int clone(int now){ cnt++; tr[cnt]=tr[now]; return cnt; } int update(int now,int l,int r,int x,int k){ now=clone(now); if(l==r){ tr[now].v+=k; return now; } int mid=(l+r)/2; if(x<=mid)tr[now].l=update(tr[now].l,l,mid,x,k); else tr[now].r=update(tr[now].r,mid+1,r,x,k); pushup(now); return now; } int query(int l,int r,int nowx,int nowy,int k){ if(l==r)return l; int sum=tr[tr[nowy].l].vtr[tr[nowx].l].v; int mid=(l+r)/2; if(k<=sum)return query(l,mid,tr[nowx].l,tr[nowy].l,k); else return query(mid+1,r,tr[nowx].r,tr[nowy].r,ksum); } void solve(){ root[0]=build(0,1,n); for(int i=1;i<=n;i++)root[i]=update(root[i1],1,n,a[seg[i]],1); for(int i=1;i<=n;i++)cout<<id[query(1,n,root[in[i]1],root[out[i]],k[i])]<<" "; } void dfs(int u,int fa){ in[u]=++top; seg[top]=u; for(int i=vex[u];i;i=e[i].next){ int v=e[i].v; if(v==fa)continue; dfs(v,u); } out[u]=top; } int main(){ int u; cin>>n; for(int i=1;i<=n;i++){ cin>>u; add(i,u); add(u,i); } for(int i=1;i<=n;i++){ cin>>a[i]; id[a[i]]=i; } for(int i=1;i<=n;i++)cin>>k[i]; dfs(1,0); solve(); return 0; }
Method 3: DFS sequence + dsu + balanced tree
Tested by: Bei
summary
 The examiner's first reaction is also dfs preface + chairman tree. The person who wrote the question above has written it. I won't repeat it here
 Here, the examiner gives another solution: D F S order + d s u + flat Weigh tree DFS order + dsu + balanced tree DFS order + dsu + balanced tree
Algorithm idea
 No matter what kind of practice, there is a core idea  "sub tree Mo team"
 What Mo team does is to lock each query interval in its own order. Here, the subtree is the query interval, so it is called sub tree Mo team. Moreover, they are all offline. All queries are stored first, and then processed uniformly.
 The idea of dsu on tree is to recursively calculate the answer of the light son each time (not added to the balance tree), then calculate the answer of the heavy son (added to the balance tree), and then add back the contributions of all the light sons to calculate the answer of the whole tree
 If the current subtree is not someone else's heavy son, it will be deleted from the balance tree
 It can be summarized as follows: the light son is not retained in the balance tree, and the heavy son is retained in the balance tree
 The total time complexity is O ( n log n ) O(n\log n) O(nlogn)
operating efficiency
 You can see the running results. It only takes less than 200 milliseconds
 However, the core of our investigation is the algorithm idea. We don't deliberately card everyone's constant, so we give 1000ms
code implementation
#include <bits/stdc++.h> #include <bits/extc++.h> #include <unordered_map> #include <unordered_set> using namespace std; using namespace __gnu_cxx; using namespace __gnu_pbds; #define debug(x) cerr << #x << ": " << x << '\n' #define bd cerr << "" << el #define el '\n' #define cl putchar('\n') #define pb push_back #define eb emplace_back #define x first #define y second #define rep(i, a, b) for (int i = (a); i <= (b); i++) #define loop(i, a, b) for (int i = (a); i < (b); i++) #define dwn(i, a, b) for (int i = (a); i >= (b); i) #define ceil(a, b) (a + (b  1)) / b #define ms(a, x) memset(a, x, sizeof(a)) #define inf 0x3f3f3f3f #define db double typedef long long LL; typedef long double LD; typedef pair<int, int> PII; typedef pair<db, db> PDD; typedef vector<int> vci; inline int read() { int f = 1, d = 0; char ch; ch = getchar(); while (ch < '0'  ch > '9') { if (ch == '') f = 1; ch = getchar(); } while (ch >= '0' && ch <= '9') d = (d << 1) + (d << 3) + (ch ^ 48), ch = getchar(); return d * f; } const int N = 1e5 + 10, M = 2e6 + 10, E = 1e3 + 10, md = 1e9 + 7; const double PI = acos(1), eps = 1e8; int T, n, m, k; LL a[N]; vector<int> g[N]; int qry[N], ans[N]; typedef tree<PII, null_type, less<PII>, rb_tree_tag, tree_order_statistics_node_update> Tree; Tree tr; int dfn[N], iDfn[N], sz[N], son[N], dfs_clock; void merge(int cur, bool isSon) { for (int ver : g[cur]) if (ver != son[cur]) merge(ver, false); if (son[cur]) //If a heavy son exists merge(son[cur], true); for (int ver : g[cur]) if (ver != son[cur]) for (int i = dfn[ver]; i < dfn[ver] + sz[ver]; i++) tr.insert(make_pair(a[iDfn[i]], iDfn[i])); tr.insert(make_pair(a[cur], cur)); ans[cur] = (*tr.find_by_order(qry[cur]  1)).second; if (!isSon) //If it's not a heavy son for (int i = dfn[cur]; i < dfn[cur] + sz[cur]; i++) tr.erase(make_pair(a[iDfn[i]], iDfn[i])); } void dfs(int cur, int pre) //Generate dfs order { dfn[cur] = ++dfs_clock; iDfn[dfs_clock] = cur; sz[cur] = 1; for (int ver : g[cur]) { dfs(ver, cur); sz[cur] += sz[ver]; //Calculates the size of the current subtree if (!son[cur]  sz[ver] > sz[son[cur]]) son[cur] = ver; //Looking for a heavy son } } int main() { cout.tie(0); n = read(); rep(i, 1, n) { k = read(); g[k].pb(i); } rep(i, 1, n) a[i] = read(); rep(i, 1, n) qry[i] = read(); dfs(1, 0); //Get dfs order merge(1, 1); //By default, 1 is also a duplicate son, omitting the last deletion and optimizing for (int i = 1; i <= n; i++) cout << ans[i] << ' '; }
L33 triplet
Author: Bei
Author's Report
 Originally, I put this question as a delivery proposition. It also requires a deep level of algorithm (may, the first level of selection?) to write violence forcibly. It takes about 70 minutes to get 5 points. If the problem is solved correctly, it will not be done if the problem is solved.
 But then I changed the question. After all, the ABC question group is in power now, not to embarrass everyone, but to produce a highquality paper with distinction.
 So I changed to this one. As for the original question, I got the followup to you.
 I set up four test points
 Test point 1: n 1 = n 2 = n 3 = 50 n_1=n_2=n_3=50 n1 = n2 = n3 = 50, tripartite violence can pass, 2 points
 Test point 2: n 1 = 100 , n 2 = 1000 , n 3 = 1 e 5 n_1=100,n_2=1000,n3=1e5 n1 = 100,n2 = 1000,n3=1e5, mustset can pass, 5 points
 Test point 3: n 1 = 32343 , n 2 = 50097 , n 3 = 96675 n_1=32343,n_2 = 50097,n_3=96675 n1 = 32343,n2 = 50097,n3 = 96675, FFT can pass, 11 points
 Test point 4: n 1 = n 2 = n 3 = 1 e 5 n1=n2=n3=1e5 n1=n2=n3=1e5, the FFT is OK, the long long (WA) is stuck out, and the FFT template (TLE) with too large constant, 12 points.
Algorithm idea
Algorithm 1: cubic violence, 2 points
 There's nothing to say. There are three cycles without brain
 Time complexity O ( n 3 ) O(n^3) O(n3)
code implementation
#define el '\n' #define rep(i, a, b) for (int i = (a); i <= (b); i++) int main() { cin.tie(0); cout.tie(0); cin >> n1; rep(i, 1, n1) cin >> a[i]; cin >> n2; rep(i, 1, n2) cin >> b[i]; cin >> n3; rep(i, 1, n3) cin >> c[i]; LL cnt = 0; rep(i, 1, n1) rep(j, 1, n2) rep(k, 1, n3) if(a[i] + b[j] + c[k] == 0) cnt ++ ; cout << cnt << el; }
Algorithm 2: multiset, 7 points
 Because the array itself may have the same value, we should use multiset. If there are only two arrays, how can we use mutiset?
*Find the opposite number!  So we can n 2 n^2 n2 in m u l t i s e t multiset multiset, and then look it up
 The range given in hint is convenient for players. Put those two arrays into multiset because n1*n2==n3
Complexity analysis
 Time complexity, will a , b a,b a. B insert the elements in the array m u l t i s e t multiset Required in multiset n 1 × n 2 n_1\times n_2 n1 × n2 times, total queries required n 3 n_3 n3 # times, and the operations of inserting and querying are O ( log ( n 1 × n 2 ) ) O(\log (n_1\times n_2)) O(log(n1 × n2), the total time complexity is O ( n 1 × n 2 × log ( n 1 × n 2 ) + n 3 log ( n 1 × n 2 ) ) O(n_1 \times n_2 \times \log (n_1\times n_2) + n_3 \log (n_1 \times n_2)) O(n1×n2×log(n1×n2)+n3log(n1×n2))
 Of course, at the end of the title, I give the data, this way m u l t i s e t multiset multiset is n 1 , n 2 n_1,n_2 n1, n2 because there is a data in the title n 1 × n 2 = n 3 n_1\times n_2 =n_3 n1 × n2 = n3. I also hope some firstteam seed players can calculate the complexity (I originally planned to release n 1 , n 3 n_1,n_3 n1, n3 ， because people's habitual thinking is to put two consecutive ones n 1 , n 2 n_1,n_2 n1, n2, or n 2 , n 3 n_2,n_3 n2, n3 ， so it's hard to get these 7 points. Finally, I didn't do that. The difficulty of violence is reduced a little. Otherwise, only the seed players of the first team can calculate the corresponding complexity and get the 7 points of violence)
code implementation
multiset<int> s; #define rep(i, a, b) for (int i = (a); i <= (b); i++) #define el '\n' int main() { cin.tie(0); cout.tie(0); cin >> n1; rep(i, 1, n1) cin >> a[i]; cin >> n2; rep(i, 1, n2) cin >> b[i]; cin >> n3; rep(i, 1, n3) cin >> c[i]; rep(i, 1, n1) rep(j, 1, n2) s.insert(a[i]+b[j]); LL cnt = 0; rep(i, 1, n3) cnt += s.count(c[i]); cout << cnt << el; }
Algorithm 3: Fast Fourier transform FFT, 30 points
 This question is not intended to give people A. after all, there are only a few schools that could have FFT
 What's more, the IOI competition system has no paper materials, and it also conforms to the positioning of L33 for the level of our school
 If you don't know FFT, you can baidu by yourself. There are many learning blogs on Baidu. I won't repeat them here
 The key idea of this question is: barrel
 FFT deals with polynomial multiplication
 We all know that FFT can multiply polynomials O ( n 2 ) O(n^2) O(n2) acceleration is O ( n log n ) O(n \log n) O(nlogn)
 So the relationship between two numbers is additive. How to make it multiply? Put them all on the exponent, multiply the two power exponents, and add the exponents.
 In this way, two times of FFT can be A. it is worth noting that due to the existence of negative numbers, the overall translation is required. The minimum case is three  1e5, so 0 represents  3e5, and the real 0 is 3e5
Complexity analysis
 Time complexity, which is the complexity of FFT, O ( n log n ) O(n \log n) O(nlogn) level
code implementation
#include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int N = 600010 * 2; const double PI = acos(1); int n, m; struct Complex { //The plural structure is basically unchanged double x, y; Complex operator+(const Complex &t) const { return {x + t.x, y + t.y}; } Complex operator(const Complex &t) const { return {x  t.x, y  t.y}; } Complex operator*(const Complex &t) const { return {x * t.x  y * t.y, x * t.y + y * t.x}; } } A[N], B[N], C[N]; int rev[N], bit, tot; void fft(Complex a[], int inv) { //inv represents the direction of serialization, 1 represents the change from coefficient representation to point value representation, and  1 is the reverse; for (int i = 0; i < tot; i++) if (i < rev[i]) swap(a[i], a[rev[i]]); for (int mid = 1; mid < tot; mid <<= 1) { auto w1 = Complex({cos(PI / mid), inv * sin(PI / mid)}); for (int i = 0; i < tot; i += mid * 2) { auto wk = Complex({1, 0}); for (int j = 0; j < mid; j++, wk = wk * w1) { auto x = a[i + j], y = wk * a[i + j + mid]; a[i + j] = x + y, a[i + j + mid] = x  y; } } } } void in(int len, Complex a[]) { for (int i = 1; i <= len; ++i) { int num; scanf("%d", &num); a[num + 100000].x += 1.0; } } void _merge(Complex a[], Complex b[], int &n, int &m) { bit = 0; while ((1 << bit) < n + m + 1) bit++; tot = 1 << bit; n = tot; rev[0] = 0; //Initialize rev for (int i = 0; i < tot; i++) rev[i] = (rev[i >> 1] >> 1)  ((i & 1) << (bit  1)); fft(a, 1), fft(b, 1); for (int i = 0; i < tot; i++) a[i] = a[i] * b[i]; fft(a, 1); //The above boards do not need to be changed, just add an initialization with bit=0 for (int i = 0; i < tot; ++i) a[i].x = 1.0 * (long long)(a[i].x / tot + 0.5); } int main() { //int k; scanf("%d",&k);// Find the number of schemes with triple sum K; int lena; scanf("%d", &lena); in(lena, A); int lenb; scanf("%d", &lenb); in(lenb, B); int lenc; scanf("%d", &lenc); in(lenc, C); //input finished lena = lenb = lenc = 200000; //The range of values is polynomial length, 2e5 buckets, subscript. Negative numbers need to be shifted to the right _merge(A, B, lena, lenb); //merge _merge(A, C, lena, lenc); //merge //solved printf("%lld", (long long)(A[300000].x)); //Because the minimum value may be the sum of three 1e5, the bucket needs to be moved to the right return 0; } /* 1 2 2 2 1 2 1 0 */