Codeforces Round 881 (Div. 3) 题解

目录

A. Sasha and Array Coloring

题意:

思路:

代码:

B. Long Long

题意:

思路:

代码:

C. Sum in Binary Tree

题意:

思路:

代码:

D. Apple Tree(树形dp)

题意:

思路:

代码:

E. Tracking Segments(二分答案)

题意:

思路:

代码:

F1. Omsk Metro (simple version)(树形dp)

题意:

思路:

代码:


A. Sasha and Array Coloring

Sasha found an array a consisting of 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 max(S)−min(S) where 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], and you painted its elements into two colors as follows: elements on positions 1, 2 and 5 have color 11; elements on positions 3 and 4 have color 2. Then:

  • the cost of the color 1 is max([1,5,4])−min([1,5,4])=5−1=4
  • the cost of the color 2 is max([6,3])−min([6,3])=6−3=3;
  • the total cost of the coloring is 7.

For the given array a, you have to calculate the maximum possible cost of the coloring.

Input

The first line contains one integer 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.

The second line contains n integers a1,a2,…,an (1≤ai≤50) — array 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

题意:

给一个数组,拆分成若干个子序列,求所有子序列最大值减最小值的和

思路:

贪心,每次选最大的和最小的两个数组成一个子序列

代码:

#include<bits/stdc++.h>
#define endl '\n'
#define debug(x) cout<<#x<<'='<<x<<endl;
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
const int INF=0x3f3f3f3f;

#define int long long
void solve(){
    int n;
    cin>>n;
    int ans=0;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++)cin>>a[i];
    sort(a.begin()+1,a.end());
    for(int i=1;i<=n;i++){
        int l=i,r=n+1-i;
        if(l<r)ans+=a[r]-a[l];
        else break;
    }
    cout<<ans<<endl;
    return;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int T=1;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}


B. Long Long

Today Alex was brought array a1,a2,…,an of length n. He can apply as many operations as he wants (including zero operations) to change the array elements.

In 11 operation Alex can choose any l and r such that 1≤l≤r≤n, and multiply all elements of the array from l to r inclusive by −1−1. In other words, Alex can replace the subarray [al,al+1,…,ar] by [−al,−al+1,…,−ar] in 11 operation.

For example, let n=5, the array is [1,−2,0,3,−1], l=2 and r=4, then after the operation the array will be [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 single integer 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⋅105) — length of the array.

The second line contains n integers a1,a2,…,an (−109≤ai≤109) — elements of the array.

It is guaranteed that the sum of n for all test cases does not exceed 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

题意:

给一个序列,每次把一个区间内的数取相反数,求全部变正的最小次数和最后的元素和

思路:

贪心,从头开始,如果需要取反,则以当前点为起点往后尽可能延伸

代码:

#include<bits/stdc++.h>
#define endl '\n'
#define debug(x) cout<<#x<<'='<<x<<endl;
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
const int INF=0x3f3f3f3f;

#define int long long
void solve(){
    int n;
    cin>>n;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++)cin>>a[i];
    int ans=0;
    int cnt=0;
    int flag=0;
    for(int i=1;i<=n;i++){
        if(a[i]>0){
            flag=0;
            ans+=a[i];
        }
        else{
            ans-=a[i];
            if(flag==0&&a[i]<0){
                flag=1;
                cnt++;
            }
        }
    }
    cout<<ans<<' '<<cnt<<endl;
    return;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int T=1;
    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 11 — the root of the tree. Then, Vanya adds two children to it, assigning them consecutive numbers — 22 and 33, respectively. After that, he will add children to the vertices in increasing order of their numbers, starting from 22, assigning their children the minimum unused indices. As a result, Vanya will have an infinite tree with the root in the vertex 11, 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 11 to the vertex with number 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≤104) — the number of test cases.

This is followed by  t lines — the description of the test cases. Each line contains one integer 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

题意:

对于一个完全二叉树,求根节点到n号节点的路径和

思路:

不断往上跳即可

代码:

#include<bits/stdc++.h>
#define endl '\n'
#define debug(x) cout<<#x<<'='<<x<<endl;
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
const int INF=0x3f3f3f3f;

#define int long long
void solve(){
    int n;
    cin>>n;
    int ans=0;
    while(n!=1){
        ans+=n;
        n/=2;
    }
    cout<<ans+1<<endl;
    return;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int T=1;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}


D. Apple Tree(树形dp)

Timofey has an apple tree growing in his garden; it is a rooted tree of n vertices with the root in vertex 1 (the vertices are numbered from 1 to 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.

  • If a vertex 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 assumptions in which vertices apples can grow. He assumes that apples can grow in vertices x and y, and wants to know the number of pairs of vertices (a, b) from which apples can fall from the tree, where a — the vertex from which an apple from vertex x will fall, b — the vertex from which an apple from vertex y will fall. Help him do this.

Input

The first line contains integer t (1≤t≤104) — the number of test cases.

The first line of each test case contains integer n (2≤n≤2⋅105) — the number of vertices in the tree.

Then there are n−1 lines describing the tree. In line i there are two integers ui and vi (1≤ui,vi≤n, ui≠vi) — edge in tree.

The next line contains a single integer q (1≤q≤2⋅105) — the number of Timofey's assumptions.

Each of the next q lines contains two integers xi and yi (1≤xi,yi≤n) — the supposed vertices on which the apples will grow for the assumption i.

It is guaranteed that the sum of n does not exceed 2⋅105. Similarly, It is guaranteed that the sum of q does not exceed 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.

Examples

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

题意:

给一棵有根树,树上有两个苹果,沿着儿子往下掉落,最终位于叶子,求可能的掉落位置数对(pos1,pos2)的个数

思路:

树形dp,dfs统计每个点形成的子树的根节点个数即可,边界为叶子节点(度为1判断)

每次询问,O(1) 计算每个苹果的掉落位置并相乘

代码:

#include<bits/stdc++.h>
#define endl '\n'
#define debug(x) cout<<#x<<'='<<x<<endl;
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
const int INF=0x3f3f3f3f;

#define int long long
const int N=200005,M=200005;

int head[N],cntt=0;
struct Edge{
    int to,next,val;
}edge[2*M];
void add(int u,int v,int x){
    edge[++cntt].to=v;
    edge[cntt].val=x;
    edge[cntt].next=head[u];
    head[u]=cntt;
}

int dp[N],dis[N],du[N];
void dfs(int x){
    dp[x]=0;
    if(du[x]==1&&x!=1){
        dp[x]=1;
        return;
    }
    for(int i=head[x];i;i=edge[i].next){
        int y=edge[i].to;
        if(dis[y])continue;
        dis[y]=dis[x]+1;
        dfs(y);
        dp[x]+=dp[y];
    }
}
void solve(){
    int n;
    cin>>n;
    cntt=0;
    for(int i=1;i<=n;i++)head[i]=0,dis[i]=0,dp[i]=0,du[i]=0;
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        du[u]++,du[v]++;
        add(u,v,1);
        add(v,u,1);
    }
    dis[1]=1;
    dfs(1);
    int q;
    cin>>q;
    while(q--){
        int u,v;
        cin>>u>>v;
        cout<<dp[u]*dp[v]<<endl;
    }
    return;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int T=1;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}


E. Tracking Segments(二分答案)

You are given an array a consisting of n zeros. You are also given a set of m not necessarily different segments. Each segment is defined by two numbers li and ri (1≤li≤ri≤n) and represents a subarray ali,ali+1,…,ari of the array a.

Let's call the segment li,ri beautiful if the number of ones on this segment is strictly greater than the number of zeros. For example, if a=[1,0,1,0,1], then the segment [1,5] is beautiful (the number of ones is 3, the number of zeros is 2), but the segment [3,4] is not is beautiful (the number of ones is 1, the number of zeros is 1).

You also have q changes. For each change you are given the number 1≤x≤, which means that you must assign an element 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 changes.

Input

The first line contains a single integer t (1≤t≤104) — the number of test cases.

The first line of each test case contains two integers n and m (1≤m≤n≤105) — the size of the array a and the number of segments, respectively.

Then there are m lines consisting of two numbers li and ri (1≤li≤ri≤n) —the boundaries of the segments.

The next line contains an integer q (1≤q≤n) — the number of changes.

The following q lines each contain a single integer x (1≤x≤n) — the index of the array element that needs to be set to 1 It is guaranteed that indexes in queries are distinct.

It is guaranteed that the sum of n for all test cases does not exceed 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 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的全为0的数组,给m个线段,有q次操作顺序执行,每次将位置x的数变成1

求满足 某一个线段 1的个数大于0的个数 的最小操作次数

思路:

发现操作次数具有单调性,可以二分答案,用前缀和预处理,可以O(1)求出 线段 中1的个数,暴力判断能否满足,复杂度为O(mlogq)

代码:

#include<bits/stdc++.h>
#define endl '\n'
#define debug(x) cout<<#x<<'='<<x<<endl;
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
const int INF=0x3f3f3f3f;
#define int long long
const int N=100005;

int op[N],ans[N],l[N],r[N];
int n,m;

bool check(int x){
    vector<int>vis(n+1,0),pre(n+1,0);
    for(int i=1;i<=x;i++)vis[op[i]]=1;
    for(int i=1;i<=n;i++)pre[i]=pre[i-1]+vis[i];
    for(int i=1;i<=m;i++)
        if(pre[r[i]]-pre[l[i]-1]>=ans[i])return 1;
    return 0;
}

void solve(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>l[i]>>r[i];
        ans[i]=(r[i]-l[i]+1)/2+1;
    }
    int q;
    cin>>q;
    for(int i=1;i<=q;i++)cin>>op[i];
    int l=1,r=q;
    while(l<r){
        int mid=(l+r)/2;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    if(check(l)){
        cout<<l<<endl;
        return;
    }
    cout<<-1<<endl;
    return;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int T=1;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}


F1. Omsk Metro (simple version)(树形dp)

This is the simple version of the problem. The only difference between the simple and hard versions is that in this version 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∈{−1,1}. If the station has a weight of −1−1, then when the station is visited by an Omsk resident, a fee of 11 burle is charged. If the weight of the station is 11, then the Omsk resident is rewarded with 11 burle.

Omsk Metro currently has only one station with number 11 and weight x=1. Every day, one of the following events occurs:

  • A new station with weight x is added to the station with number 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 uand v such that, by traveling along it, exactly k burles can be earned (if k<0, this mens that 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. Note that the subsegment can be empty, and then the sum is equal to 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≤104) — the number of test cases.

The first line of each test case contains the number n (1≤n≤2⋅105) — the number of events.

Then there are n lines describing the events. In the i-th line, one of the following options is possible:

  • First comes the symbol "+" (without quotes), then two numbers vi and xi (xi∈{−1,1}, it is also guaranteed that the vertex with number vi exists). In this case, a new station with weight xi is added to the station with number vi.
  • First comes the symbol "?" (without quotes), and then three numbers ui, vi, and ki (−n≤ki≤n). It is guaranteed that the vertices with numbers ui and vi exist. In this case, it is necessary to determine whether there is a subsegment (possibly empty) of the path between stations ui and vi with a sum of weights exactly equal to ki. In this version of the task, it is guaranteed that ui=1

It is guaranteed that the sum of n over all test cases does not exceed 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

题意:

给一棵有根树,每次给定点 v,询问从根节点到 v 路径上的某个字段的和能否等于k

思路:

树形dp,我们发现每个点的值是1或-1,所以 所有字段和 形成的区间是连续的,中间不会出现断点,我们用dp数组记录当前点必须选的最值,用 mx/mn 记录整体最值,状态转移方程为dpmax[cnt]=max(x,dpmax[v]+x) ,每个点v能取的区间就是 [mn,mx] ,判断即可

代码:

#include<bits/stdc++.h>
#define endl '\n'
#define debug(x) cout<<#x<<'='<<x<<endl;
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
const int INF=0x3f3f3f3f;

#define int long long

void solve(){
    int n;
    cin>>n;
    int cnt=1;
    vector<int>dpmax(n+10),dpmin(n+10),mx(n+10),mn(n+10);
    dpmax[1]=1;
    dpmin[1]=1;
    mx[1]=1;
    mn[1]=0;
    for(int _=1;_<=n;_++){
        char op;
        cin>>op;
        if(op=='+'){
            int v,x;
            cin>>v>>x;
            cnt++;
            dpmax[cnt]=max(x,dpmax[v]+x);
            dpmin[cnt]=min(x,dpmin[v]+x);
            mx[cnt]=max(mx[v],dpmax[cnt]);
            mn[cnt]=min(mn[v],dpmin[cnt]);
        }
        else{
            int u,v,x;
            cin>>u>>v>>x;
            //u=1
            if(x>=mn[v]&&x<=mx[v])cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
    }
    return;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int T=1;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Auroraaaaaaaaaaaaa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值