CF Round 881 Div.3
A. Sasha and Array Coloring
题面
Sasha found an array a a a consisting of n n n integers and asked you to paint elements.
You have to paint each element of the array. You can use as many colors as you want, but each element should be painted into exactly one color, and for each color, there should be at least one element of that color.
The cost of one color is the value of m a x ( S ) − m i n ( S ) max(S)−min(S) max(S)−min(S), where S S S is the sequence of elements of that color. The cost of the whole coloring is the sum of costs over all colors.
For example, suppose you have an array a = [ 1 , 5 , 6 , 3 , 4 ] a=\left[1,5,6,3,4 \right] a=[1,5,6,3,4], and you painted its elements into two colors as follows: elements on positions 1 , 2 1, 2 1,2 and 5 5 5 have color 1 1 1; elements on positions 3 3 3 and 4 4 4 have color 2 2 2. Then:
- the cost of the color 1 1 1 is m a x ( [ 1 , 5 , 4 ] ) − m i n ( [ 1 , 5 , 4 ] ) = 5 − 1 = 4 max([1,5,4])−min([1,5,4])=5−1=4 max([1,5,4])−min([1,5,4])=5−1=4;
- the cost of the color 2 2 2 is m a x ( [ 6 , 3 ] ) − m i n ( [ 6 , 3 ] ) = 6 − 3 = 3 max([6,3])−min([6,3])=6−3=3 max([6,3])−min([6,3])=6−3=3;
- the total cost of the coloring is 7 7 7.
For the given array a a a, you have to calculate the maximum possible cost of the coloring.
Input
The first line contains one integer t ( 1 ≤ t ≤ 1000 ) t(1≤t≤1000) t(1≤t≤1000) — the number of test cases.
The first line of each test case contains a single integer $n (1≤n≤50) $— length of a a a.
The second line contains n n n integers a 1 , a 2 , … , a n ( 1 ≤ a i ≤ 50 ) a_{1},a_{2},\dots,a_{n} (1≤a_{i}≤50) a1,a2,…,an(1≤ai≤50) — array a a a.
Output
For each test case output the maximum possible cost of the coloring.
Example
input
6
5
1 5 6 3 4
1
5
4
1 6 3 9
6
1 13 9 3 7 2
4
2 2 2 2
5
4 5 2 2 3
output
7
0
11
23
0
5
题意
给你一个数组 a a a,对其染色,求每种颜色的最大和最小之差之和。
笨蒟蒻的个人题解
排序+双指针,非常简单。
AC_Code
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
#define int long long
#define fi first
#define se second
typedef pair<int, int> PII;
const int N = 500 + 10;
int T, n;
int a[N];
void solve()
{
int ans = 0;
scanf("%lld", &n);
for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
sort(a + 1, a + 1 + n);
for(int i = 1, j = n; i <= j - 1; i++, j--)
{
ans += (a[j] - a[i]);
}
cout << ans << endl;
}
signed main()
{
cin >> T;
while(T--)
solve();
return 0;
}
B. Long Long
题面
Today Alex was brought array a 1 , a 2 , … , a n a_{1},a_{2},\dots,a_{n} a1,a2,…,an of length n n n. He can apply as many operations as he wants (including zero operations) to change the array elements.
In 1 1 1 operation Alex can choose any l l l and r r r such that 1 ≤ l ≤ r ≤ n 1≤l≤r≤n 1≤l≤r≤n, and multiply all elements of the array from l l l to r r r inclusive by − 1 −1 −1. In other words, Alex can replace the subarray [ a l , a l + 1 , … , a r ] \left[a_{l},a_{l+1},\dots,a_{r} \right] [al,al+1,…,ar] by [ − a l , − a l + 1 , … , − a r ] [−a_{l},−a_{l+1},\dots,−a_{r}] [−al,−al+1,…,−ar] in 1 1 1 operation.
For example, let n = 5 n=5 n=5, the array is [ 1 , − 2 , 0 , 3 , − 1 ] \left[1,−2,0,3,−1\right] [1,−2,0,3,−1], l = 2 l=2 l=2 and r = 4 r=4 r=4, then after the operation the array will be [ 1 , 2 , 0 , − 3 , − 1 ] \left[1,2,0,−3,−1\right] [1,2,0,−3,−1].
Alex is late for school, so you should help him find the maximum possible sum of numbers in the array, which can be obtained by making any number of operations, as well as the minimum number of operations that must be done for this.
Input
The first line contains a a a single integer t ( 1 ≤ t ≤ 1 0 4 ) t (1≤t≤10^{4}) t(1≤t≤104) — number of test cases. Then the descriptions of the test cases follow.
The first line of each test case contains one integer n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 ) n (1≤n≤2⋅10^{5}) n(1≤n≤2⋅105) — length of the array.
The second line contains n n n integers a 1 , a 2 , … , a n ( − 1 0 9 ≤ a i ≤ 1 0 9 ) a_{1},a_{2},\dots,a_{n} (−10^{9}≤a_{i}≤10^{9} ) a1,a2,…,an(−109≤ai≤109) — elements of the array.
It is guaranteed that the sum of n n n for all test cases does not exceed 2 ⋅ 1 0 5 2⋅10^{5} 2⋅105 .
Output
For each test case output two space-separated numbers: the maximum possible sum of numbers in the array and the minimum number of operations to get this sum.
Pay attention that an answer may not fit in a standard integer type, so do not forget to use 64-bit integer type.
Example
input
5
6
-1 7 -4 -2 5 -8
8
-1 0 0 -2 1 0 -3 0
5
2 -1 0 -3 -7
5
0 -17 0 1 0
4
-1 0 -2 -1
output
27 3
7 2
13 1
18 1
4 1
题意
给一个数组,然后你可以在任意区间将每个数取反,问取反后最大值和最少多少次取反?
笨蒟蒻的个人题解
模拟一遍即可,非常简单。
AC_Code
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<vector>
#include<cmath>
using namespace std;
#define int long long
#define fi first
#define se second
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int T, n;
int a[N];
void solve()
{
int ans1 = 0, ans2 = 0;
scanf("%lld", &n);
bool flag = false;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
ans1 += abs(a[i]);
if(a[i] == 0) continue;
if(!flag && a[i] < 0)
{
flag = true;
ans2++;
}
else if(a[i] > 0) flag = false;
}
cout << ans1 << ' ' << ans2 << endl;
}
signed main()
{
cin >> T;
while(T--)
solve();
return 0;
}
C. Sum in Binary Tree
Vanya really likes math. One day when he was solving another math problem, he came up with an interesting tree. This tree is built as follows.
Initially, the tree has only one vertex with the number 1 1 1 — the root of the tree. Then, Vanya adds two children to it, assigning them consecutive numbers — 2 2 2 and 3 3 3 , respectively. After that, he will add children to the vertices in increasing order of their numbers, starting from 2 2 2 , assigning their children the minimum unused indices. As a result, Vanya will have an infinite tree with the root in the vertex 1 1 1 , where each vertex will have exactly two children, and the vertex numbers will be arranged sequentially by layers. Part of Vanya’s tree.
Vanya wondered what the sum of the vertex numbers on the path from the vertex with number 1 1 1 to the vertex with number n n n in such a tree is equal to. Since Vanya doesn’t like counting, he asked you to help him find this sum.
Input
The first line contains a single integer $t (1≤t≤10^{4} ) $— the number of test cases. This is followed by t t t lines — the description of the test cases. Each line contains one integer n ( 1 ≤ n ≤ 1 0 16 ) n(1≤n≤10^{16} ) n(1≤n≤1016) — the number of vertex for which Vanya wants to count the sum of vertex numbers on the path from the root to that vertex.
Output
For each test case, print one integer — the desired sum.
Example
input
6
3
10
37
1
10000000000000000
15
output
4
18
71
1
19999999999999980
26
题意
一个完全二叉树,从 1 1 1 到 n n n,然后问你求从 1 1 1 出发到叶子的路径和的最大值是多少?
笨蒟蒻的个人题解
一丢丢思维,画一下就可以出来的,就是从最大的叶子开始,往上找较大的父节点,非常简单。
AC_Code
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<vector>
using namespace std;
#define int long long
#define fi first
#define se second
typedef pair<int, int> PII;
const int N = 1e5 + 10;
int T, n, ans;
void solve()
{
scanf("%lld", &n);
ans = 0;
while(n)
{
ans += n;
n /= 2;
}
cout << ans << endl;
}
signed main()
{
cin >> T;
while(T--)
solve();
return 0;
}
D. Apple Tree
题面
Timofey has an apple tree growing in his garden; it is a rooted tree of n vertices with the root in vertex 1 1 1 (the vertices are numbered from 1 1 1 to n n n ). A tree is a connected graph without loops and multiple edges.
This tree is very unusual — it grows with its root upwards. However, it’s quite normal for programmer’s trees.
The apple tree is quite young, so only two apples will grow on it. Apples will grow in certain vertices (these vertices may be the same). After the apples grow, Timofey starts shaking the apple tree until the apples fall. Each time Timofey shakes the apple tree, the following happens to each of the apples:
- Let the apple now be at vertex u u u . If a vertex u u u has a child, the apple moves to it (if there are several such vertices, the apple can move to any of them).
- Otherwise, the apple falls from the tree. It can be shown that after a finite time, both apples will fall from the tree.
Timofey has q q q assumptions in which vertices apples can grow. He assumes that apples can grow in vertices x x x and y y y , and wants to know the number of pairs of vertices ( a , b ) (a , b ) (a,b) from which apples can fall from the tree, where a a a — the vertex from which an apple from vertex x x x will fall, b b b — the vertex from which an apple from vertex y y y will fall. Help him do this.
Input
The first line contains integer t ( 1 ≤ t ≤ 1 0 4 ) t (1≤t≤10^4 ) t(1≤t≤104) — the number of test cases.
The first line of each test case contains integer n ( 2 ≤ n ≤ 2 ⋅ 1 0 5 ) n (2≤n≤2⋅10^5 ) n(2≤n≤2⋅105) — the number of vertices in the tree.
Then there are n − 1 n−1 n−1 lines describing the tree. In line i i i there are two integers u i u_{i} ui and v i ( 1 ≤ u i , v i ≤ n , u i ≠ v i ) v_{i} (1≤u_{i},v_{i}≤n , u_{i}≠v_{i} ) vi(1≤ui,vi≤n,ui=vi) — edge in tree. The next line contains a single integer q ( 1 ≤ q ≤ 2 ⋅ 1 0 5 ) q (1≤q≤2⋅10^5 ) q(1≤q≤2⋅105) — the number of Timofey’s assumptions.
Each of the next q q q lines contains two integers x i x_{i} xi and y i ( 1 ≤ x i , y i ≤ n ) y_{i} (1≤x_{i},y_{i}≤n ) yi(1≤xi,yi≤n) — the supposed vertices on which the apples will grow for the assumption i i i .
It is guaranteed that the sum of n n n does not exceed 2 ⋅ 1 0 5 2⋅10^5 2⋅105 . Similarly, It is guaranteed that the sum of q q q does not exceed 2 ⋅ 1 0 5 2⋅10^5 2⋅105 .
Output
For each Timofey’s assumption output the number of ordered pairs of vertices from which apples can fall from the tree if the assumption is true on a separate line.
Example
input
2
5
1 2
3 4
5 3
3 2
4
3 4
5 1
4 4
1 3
3
1 2
1 3
3
1 1
2 3
3 1
output
2
2
1
4
4
1
2
input
2
5
5 1
1 2
2 3
4 3
2
5 5
5 1
5
3 2
5 3
2 1
4 2
3
4 3
2 1
4 2
output
1
2
1
4
2
题意
一个苹果树,然后 q q q 个询问,告诉你任意两个结点 a a a 和 b b b,每次都有两种操作。第一种:如果不在叶子结点,就随意的掉到其中一个叶子结点,第二种:如果在叶子结点,就掉到地上。直到都掉到地上位置,然后问你有掉在叶子结点的组合的数量?
笨蒟蒻的个人题解
首先先观察一下这个题意,假设 a a a 能掉在叶子结点的数量有 x 1 x1 x1 个, b b b 能掉在叶子结点的数量有 x 2 x2 x2 个,那么这题的组合就非常好算了,答案就是 x 1 × x 2 x1 \times x2 x1×x2。那么这题就转化为求任意一个结点,他所拥有的叶子结点的个数是多少了?
AC_Code
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<vector>
using namespace std;
#define int long long
#define fi first
#define se second
typedef pair<int, int> PII;
const int N = 2e5 + 10, M = N * 2;
int T, n, q, ans;
int e[M], ne[M], h[N], idx;
int s[N], p[N], d[N];
vector<int> v;
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u, int fa)
{
for(int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if(j == fa) continue;
p[j] = u;
dfs(j, u);
d[u] += d[j];
}
}
void solve()
{
v.clear();
idx = 0;
scanf("%lld", &n);
for(int i = 0; i <= n * 2; i++) h[i] = -1;
for(int i = 1; i <= n; i++) d[i] = 0, s[i] = 0;
for(int i = 1; i < n; i++)
{
int a, b;
scanf("%lld%lld", &a, &b);
add(a, b), add(b, a);
s[a]++, s[b]++;
}
for(int i = 2; i <= n; i++)
if(s[i] == 1) d[i]++;
p[1] = -1;
dfs(1, -1);
scanf("%lld", &q);
while(q--)
{
int l, r;
scanf("%lld%lld", &l, &r);
cout << d[l] * d[r] << endl;
}
}
signed main()
{
cin >> T;
while(T--)
solve();
return 0;
}
E. Tracking Segments
题面
You are given an array a a a consisting of n n n zeros. You are also given a set of m not necessarily different segments. Each segment is defined by two numbers l i l_{i} li and r i ( 1 ≤ l i ≤ r i ≤ n ) r_{i} (1≤l_{i}≤r_{i}≤n ) ri(1≤li≤ri≤n) and represents a subarray a l i , a l i + 1 , … , a r i a_{l_{i}},a_{l_{i+1}},\dots,a_{r_{i}} ali,ali+1,…,ari of the array a a a .
Let’s call the segment l i , r i l_{i},r_{i} li,ri beautiful if the number of ones on this segment is strictly greater than the number of zeros. For example, if $a=\left[1,0,1,0,1\right] $, then the segment [ 1 , 5 ] [1,5] [1,5] is beautiful (the number of ones is 3 3 3 , the number of zeros is 2 2 2 ), but the segment [ 3 , 4 ] [3,4] [3,4] is not is beautiful (the number of ones is 1 1 1 , the number of zeros is 1 1 1 ).
You also have q q q changes. For each change you are given the number 1 ≤ x ≤ n 1≤x≤n 1≤x≤n , which means that you must assign an element a x a_{x} ax the value 1 .
You have to find the first change after which at least one of m given segments becomes beautiful, or report that none of them is beautiful after processing all q q q changes.
Input
The first line contains a single integer t ( 1 ≤ t ≤ 1 0 4 ) t (1≤t≤10^4 ) t(1≤t≤104) — the number of test cases.
The first line of each test case contains two integers n n n and m ( 1 ≤ m ≤ n ≤ 1 0 5 ) m (1≤m≤n≤10^5 ) m(1≤m≤n≤105) — the size of the array a a a and the number of segments, respectively.
Then there are m m m lines consisting of two numbers l i l_{i} li and r i ( 1 ≤ l i ≤ r i ≤ n ) r_{i} (1≤l_{i}≤r_{i}≤n ) ri(1≤li≤ri≤n) —the boundaries of the segments.
The next line contains an integer q ( 1 ≤ q ≤ n ) q (1≤q≤n) q(1≤q≤n) — the number of changes.
The following q q q lines each contain a single integer x ( 1 ≤ x ≤ n ) x (1≤x≤n ) x(1≤x≤n) — the index of the array element that needs to be set to 1 1 1 . It is guaranteed that indexes in queries are distinct.
It is guaranteed that the sum of n n n for all test cases does not exceed 1 0 5 10^5 105 .
Output
For each test case, output one integer — the minimum change number after which at least one of the segments will be beautiful, or − 1 −1 −1 if none of the segments will be beautiful.
Example
input
6
5 5
1 2
4 5
1 5
1 3
2 4
5
5
3
1
2
4
4 2
1 1
4 4
2
2
3
5 2
1 5
1 5
4
2
1
3
4
5 2
1 5
1 3
5
4
1
2
3
5
5 5
1 5
1 5
1 5
1 5
1 4
3
1
4
3
3 2
2 2
1 3
3
2
3
1
output
3
-1
3
3
3
1
题意
给你一个长度为 n n n 的数组 a a a,然后你有 m m m 个区间,再给你 q q q 个操作,每次询问给你一个 x x x ,让 a x = 1 a_{x} = 1 ax=1, 问你最少操作几次,能使得所有区间内的 1 1 1 的数量严格比 0 0 0 多?
笨蒟蒻的个人题解
如果暴力,枚举所有的 q q q 个操作,时间复杂度是 O ( t q ( n + m ) ) O(tq(n+m)) O(tq(n+m)),会超时。所以要进一步优化。这题是一个非常典型的二分答案的做法,我们可以直接二分答案,然后优化。那如何快速判断区间内的 1 1 1 的数量大于 0 0 0 的数量呢?这里观察一下可以发现,区间内只有 0 0 0 和 1 1 1,因此,我们可以使用前缀和的方法来维护,这样每次查询就是 O ( 1 ) O(1) O(1) 了,总体的时间复杂度是 O ( t l o g q ( n + m ) ) O(tlogq(n+m)) O(tlogq(n+m))。
AC_Code
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<vector>
#include<cmath>
using namespace std;
#define int long long
#define fi first
#define se second
typedef pair<int, int> PII;
const int N = 1e5 + 10;
int T, n, m, q;
int a[N], s[N];
PII p[N];
vector<int>v;
bool check(int x)
{
for(int i = 1; i <= n; i++) a[i] = 0, s[i] = 0;
for(int i = 1; i <= x; i++) a[v[i]] = 1;
for(int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i];
for(int i = 1; i <= m; i++)
{
int u = p[i].fi, w = p[i].se, k = s[w] - s[u - 1];
if(((w - u) & 1) && k >= (w - u + 1) / 2 + 1) return true;
else if((!((w - u) & 1)) && k >= (w - u) / 2 + 1) return true;
}
return false;
}
void solve()
{
scanf("%lld%lld", &n, &m);
for(int i = 1; i <= m; i++)
scanf("%lld%lld", &p[i].fi, &p[i].se);
scanf("%lld", &q);
v.resize(q + 10);
for(int i = 1; i <= q; i++)
cin >> v[i];
int l = 1, r = q;
while(l < r)
{
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
if(l != q || check(q)) cout << l << endl;
else cout << -1 << endl;
}
signed main()
{
cin >> T;
while(T--)
solve();
return 0;
}
F1. Omsk Metro (simple version)
This is the simple version of the problem. The only difference between the simple and hard versions is that in this version u = 1 u=1 u=1 .
As is known, Omsk is the capital of Berland. Like any capital, Omsk has a well-developed metro system. The Omsk metro consists of a certain number of stations connected by tunnels, and between any two stations there is exactly one path that passes through each of the tunnels no more than once. In other words, the metro is a tree.
To develop the metro and attract residents, the following system is used in Omsk. Each station has its own weight $x∈\left { -1,1 \right } $ . If the station has a weight of − 1 −1 −1 , then when the station is visited by an Omsk resident, a fee of 1 1 1 burle is charged. If the weight of the station is 1 1 1 , then the Omsk resident is rewarded with 1 1 1 burle.
Omsk Metro currently has only one station with number 1 1 1 and weight x = 1 x=1 x=1 . Every day, one of the following events occurs:
-
A new station with weight x x x is added to the station with number v i v_{i} vi, and it is assigned a number that is one greater than the number of existing stations.
-
Alex, who lives in Omsk, wonders: is there a subsegment (possibly empty) of the path between vertices u u u and v v v such that, by traveling along it, exactly k k k burles can be earned (if k < 0 k<0 k<0, this means that k k k burles will have to be spent on travel). In other words, Alex is interested in whether there is such a subsegment of the path that the sum of the weights of the vertices in it is equal to k k k. Note that the subsegment can be empty, and then the sum is equal to 0 0 0.
You are a friend of Alex, so your task is to answer Alex’s questions.
Subsegment — continuous sequence of elements.
Input
The first line contains a single number t ( 1 ≤ t ≤ 1 0 4 ) t (1≤t≤10^4 ) t(1≤t≤104) — the number of test cases.
The first line of each test case contains the number $n (1≤n≤2⋅10^5 ) $— the number of events.
Then there are n n n lines describing the events. In the i i i-th line, one of the following options is possible:
- First comes the symbol “+” (without quotes), then two numbers v i v_{i} vi and x i ( x i ∈ { − 1 , 1 } x_{i} (x_{i}∈\left \{ -1,1 \right \} xi(xi∈{−1,1}, it is also guaranteed that the vertex with number v i v_{i} vi exists). In this case, a new station with weight x i x_{i} xi is added to the station with number v i v_{i} vi.
- First comes the symbol “?” (without quotes), and then three numbers u i u_{i} ui, v i v_{i} vi, and k i ( − n ≤ k i ≤ n ) k_{i} (−n≤k_{i}≤n) ki(−n≤ki≤n). It is guaranteed that the vertices with numbers u i u_{i} ui and v i v_{i} vi exist. In this case, it is necessary to determine whether there is a subsegment (possibly empty) of the path between stations u i u_{i} ui and v i v_{i} vi with a sum of weights exactly equal to k i k_{i} ki. In this version of the task, it is guaranteed that u i = 1 u_{i}=1 ui=1.
It is guaranteed that the sum of n n n over all test cases does not exceed 2 ⋅ 1 0 5 2⋅10^5 2⋅105.
Output
For each of Alex’s questions, output “Yes” (without quotes) if the subsegment described in the condition exists, otherwise output “No” (without quotes).
You can output the answer in any case (for example, the strings “yEs”, “yes”, “Yes” and “YES” will be recognized as a positive answer).
Examples
input
1
8
+ 1 -1
? 1 1 2
? 1 2 1
+ 1 1
? 1 3 -1
? 1 1 1
? 1 3 2
? 1 1 0
output
NO
YES
NO
YES
YES
YES
input
1
10
+ 1 -1
+ 1 -1
+ 3 1
+ 3 -1
+ 3 1
? 1 6 -1
? 1 6 2
? 1 2 0
? 1 5 -2
? 1 4 3
output
YES
NO
YES
YES
NO
题意
初始条件,你有一个数字为 1 1 1,权值为 1 1 1 的结点,你有 n n n 次操作,每次操作规则如下:
1、开头是 ‘+’,你新创一个结点,数字 + 1 +1 +1,然后和 v i v_{i} vi 连接,权值为 x i x_{i} xi。
2、开头是 ‘?’,询问从 u i u_{i} ui 和 v i v_{i} vi 之间是否有一段连续的子区间(区间可以为空)的值恰好为 k k k?
笨蒟蒻的个人题解
题目已经有保证每次询问的 u i u_{i} ui 和 v i v_{i} vi 一定存在,那么这题其实可以这样,我们先把树给全部建起来,这样做是没有任何影响的。对于询问的,我们可以先存起来,那么这道题目就转化成了树上从根节点出发到某个结点的这一条路径里,是否存在一个子区间的值恰好为 k k k。
那么如何求一个子区间的连续值是否为 k k k 呢?这其实是一个 dp 问题。
我们认
d
p
[
i
]
dp[i]
dp[i] 表示以
i
i
i 为结尾的子区间的最大值(第
i
i
i 个数必须选)。那么状态转义方程就是: dp[i] = max(dp[i - 1] + a[i], a[i]);
初始条件:dp[0] = a[0];
但是这样子写太麻烦了,完全可以这样代替。pre = max(pre + a[i], a[i]);
这样可以少开一个数组,优化了一下。
回归本题,这里用了 m x mx mx 表示 d p [ i ] dp[i] dp[i],然后我们 dfs 遍历的时候只需要把每个状态存下来即可。
那么本题特殊,权值只有 0 0 0 和 1 1 1,所以我们如何快速判断 k k k 是否在那个子区间里呢?只需要求一下最小连续子区间和和最大连续子区间和,然后判断 k k k 是否在这个区间内就好了呀!
注意一下 0 0 0 的特殊情况啊,由于子区间可以为空的,所以要注意啊,最大连续子区间和不能低于 0 0 0,最小连续子区间和不能超过 0 0 0。
AC_Code
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<vector>
#include<cmath>
using namespace std;
#define int long long
#define fi first
#define se second
typedef pair<int, int> PII;
const int N = 2e5 + 10, M = N * 2;
int T, n, cnt;
int e[M], ne[M], h[N], w[M], idx;
int s1[N], s2[N];
vector<PII> v;
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u, int fa, int mx, int mn)
{
mx = max(mx, 0ll), mn = min(mn, 0ll);
if(fa != -1)
{
mx = max(mx + w[u], w[u]), mn = min(mn + w[u], w[u]);
s1[u] = min(s1[fa], mn), s2[u] = max(s2[fa], mx);
}
for(int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
dfs(j, u, mx, mn);
}
}
void solve()
{
scanf("%lld", &n);
v.clear();
for(int i = 0; i <= 2 * n; i++) h[i] = -1;
idx = 0, cnt = 2;
for(int i = 1; i <= n; i++)
{
string s;
int a, b, c;
cin >> s;
if(s == "+")
{
scanf("%lld%lld", &a, &b);
w[cnt] = b;
add(a, cnt);
cnt++;
}
else
{
scanf("%lld%lld%lld", &a, &b, &c);
v.push_back({b, c});
}
}
w[1] = 1, s1[1] = 0, s2[1] = 1;
dfs(1, -1, 1, 0);
for(auto x: v)
{
int a = x.fi, b = x.se;
if(s1[a] <= b && s2[a] >= b) puts("YES");
else puts("NO");
}
}
signed main()
{
cin >> T;
while(T--)
solve();
return 0;
}
F2 难度较大,后续有时间会更!