练习记录-cf-Codeforces Round 881 (Div. 3)A-F2

E是补的 太蠢了没想到

期末考完的复健

A. Sasha and Array Coloring

题意:可以给不同数字涂上很多颜色,每个颜色的贡献是同一个颜色内的数字最大值和最小值的差

思路:排序一遍,取头和尾的差

#include<bits/stdc++.h>
#define close     std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN = 3e5+7;
const ll mod =1e9+7;
const ll inf =0x3f3f3f3f;
const ll INF =0x3f3f3f3f3f3f3f3f;
int a[MAXN];
void solve(){
    int n;cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+1+n);
    int l=1,r=n;
    int sum=0;
    while(l<=r){
        sum+=a[r]-a[l];
        r--;l++;
    }
    cout<<sum<<"\n";
}
signed main(){
    int t;
    cin>>t;
    while(t--) 
    solve();
}
View Code

B. Long Long

题意:可以选某一段区间,改变它的正负性,求整个都是正的情况的改变次数

思路:遇到第一个负的标记,随后遇到第一个正的取消标记,遇到负的再标记 标记次数就是答案

#include<bits/stdc++.h>
#define close     std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN = 3e5+7;
const ll mod =1e9+7;
const ll inf =0x3f3f3f3f;
const ll INF =0x3f3f3f3f3f3f3f3f;
#define int long long
void solve(){
    int n;cin>>n;
    int sum=0;
    int cnt=0;
    int flag=0;
    for(int i=1;i<=n;i++){
        int a;cin>>a;
        if(a<0&&flag==0) {
            flag=1;
            cnt++;
        }
        else if(a>0&&flag==1){
            flag=0;
        }
        if(a<0) sum+=(a*-1);
        else sum+=a;
    }
    cout<<sum<<" "<<cnt<<"\n";
}
signed main(){
    int t;cin>>t;
    while(t--) 
    solve();
}
View Code

C. Sum in Binary Tree

题意:给你一个点,求它到二分树顶点1的路径和

思路:这个树的性质是 父节点是子节点/2 一直除就行了

#include<bits/stdc++.h>
#define close     std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN = 3e5+7;
const ll mod =1e9+7;
const ll inf =0x3f3f3f3f;
const ll INF =0x3f3f3f3f3f3f3f3f;
#define int long long
void solve(){
    int n;cin>>n;
    int sum=0;
    while(n){
        sum+=n;
        n/=2;
    }
    cout<<sum<<'\n';
}
signed main(){
    int t;cin>>t;
    while(t--)
    solve();
}
View Code

D. Apple Tree

题意:给你一棵树,从某两个节点掉下两个苹果,问调到树的叶子上的可能性组合(有序对)

思路:用树上dfs求出每个节点连通的叶子节点个数,查询时O(1)乘一下就行了

#include<bits/stdc++.h>
#define close     std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN = 3e5+7;
const ll mod =1e9+7;
const ll inf =0x3f3f3f3f;
const ll INF =0x3f3f3f3f3f3f3f3f;
#define int ll
vector<int> adj[MAXN];
int ans[MAXN];
void dfs1(int u,int fa){
    if(u!=1&&adj[u].size()==1) ans[u]=1;
    for(auto &v:adj[u]){
        if(v==fa) continue;
        dfs1(v,u);
        ans[u]=ans[u]+ans[v];
    }
}
void solve(){
    int n;cin>>n;
    for(int i=1;i<=n;i++) adj[i].clear(),ans[i]=0;
    for(int i=1;i<n;i++){
        int u,v;cin>>u>>v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    dfs1(1,-1);
    int q;cin>>q;
    while(q--){
        int u,v;
        cin>>u>>v;
        cout<<ans[u]*ans[v]<<"\n";
    }
}
signed main(){
    close;
    int t;cin>>t;
    while(t--)
    solve();
}
View Code

E. Tracking Segments

题意:有一个线段,你会按照给定顺序(q)把上面某个位置变成1 给定一些标准子段,你需要求出在第几步变成1操作的时候 刚好有第一个标准字段中的1的个数严格大于长度的1/2 

思路:二分答案  给定一个指定步数mid 先标记所有1 我们可以通过前缀和来求出x点前有几个1 于是我们知道此时是否有标准子段满足要求就是遍历所有子段,复杂度为O(m),算其长度和里面1个数即可 因为要找这个分界点 满足二分 写一个二分查找第一个满足的点即可 总复杂度O(mlog(q))

#include<bits/stdc++.h>
#define close     std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN = 3e5+7;
const ll mod =1e9+7;
const ll inf =0x3f3f3f3f;
const ll INF =0x3f3f3f3f3f3f3f3f;
#define int ll
int n,m,q;
struct node{
    int l,r;
}N[MAXN];
int Q[MAXN];
int a[MAXN];
int pre[MAXN];
bool check(int mid){
    int flag=0;
    for(int i=1;i<=n;i++) a[i]=0,pre[i]=0;
    for(int i=1;i<=min(mid,q);i++) a[Q[i]]=1;
    for(int i=1;i<=n;i++){
        pre[i]=pre[i-1]+a[i];
    }
    for(int i=1;i<=m;i++){
        int l=N[i].l,r=N[i].r;
        if(pre[r]-pre[l-1]>((r-l+1)/2)) flag=1;
    }
    if(flag) return true;
    else return false;
}
void solve(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>N[i].l>>N[i].r;
    }
    cin>>q;
    for(int i=1;i<=q;i++){
        cin>>Q[i];
    }
    int l=1,r=inf;
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid)) r=mid-1;
        else l=mid+1;
    }
    if(l==inf||r==inf) cout<<"-1\n";
    else cout<<l<<"\n";
}
signed main(){
    close;
    int t;cin>>t; 
    while(t--)
    solve();
}
View Code

F1. Omsk Metro (simple version)

题意:题目会逐渐构建一棵树,然后询问树上一条路径u-v是否存在点权和为w的一段

f1只会问到树根的

思路:这个思路有点蠢,记录某个点从顶点过来的总的最大值,从上个点出发的最大值(上个点是负的就是0+w), 以及同理最小值 每次添加新点时更新总的Max和带上这个点的Nowmax 以及最小值 查询时看看是否在范围 就行了

//待更新

#include<bits/stdc++.h>
#define close     std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN = 3e5+7;
const ll mod =1e9+7;
const ll inf =0x3f3f3f3f;
const ll INF =0x3f3f3f3f3f3f3f3f;
int a[MAXN];
vector<int> adj[MAXN];
int Min[MAXN],Max[MAXN],Nowmax[MAXN],Nowmin[MAXN];
void solve(){
    int n;cin>>n;
    for(int i=1;i<=n;i++) a[i]=0,Min[i]=0,Max[i]=0,Nowmax[i]=0,Nowmin[i]=0;
    a[1]=1;Min[1]=0;
        Max[1]=1;
        Nowmax[1]=1;
        Nowmin[1]=0;
    int cnt=1;
    while(n--){
        char ch;cin>>ch;
        
        if(ch=='+'){
            cnt++;
            int u,w;cin>>u>>w;
            a[cnt]=w;
            Min[cnt]=min({0,w,Nowmin[u]+w,Min[u]});
            Max[cnt]=max({0,w,Nowmax[u]+w,Max[u]});
            Nowmax[cnt]=max({w,Nowmax[u]+w,0});
            Nowmin[cnt]=min({w,Nowmin[u]+w,0});
        }
        else{
            int u,v,w;
            cin>>u>>v>>w;
            if(w==0){
                cout<<"Yes\n";
                continue;
            }
            if(w<Min[v]||w>Max[v]) cout<<"No\n";
            else cout<<"Yes\n";
        }
    }
}
signed main(){
    close;
    int t;cin>>t;
    while(t--)
    solve();
}
View Code

F2.Omsk Metro (hard version)

补完啦 看的一个知乎大佬的思路以及感谢很牛的学长给我debug qwq

题意:询问树上一条路径u-v是否存在点权和为w的一段

思路:使用重链剖分解求树上路径和的思路 就是两个节点 低的往上跳一个链,然后把这个点到 链头的信息合并上去。这边统一从树的上端往下端记录,分别判断左还是右。 

 

如图所示 划分成这三条重链(随便画画意思一下) 把左右两边从上到下的链分开 左边的去左边 最后把左边反向和右边相加。方向和相加顺序如图所示

如果中间的是从上到下 就加右边 否则加左边去

(此处感谢学长的方法 我自己的是全反的 很乱)

此处的合并和求和均使用线段树维护,和维护区间最大值同理

#include<bits/stdc++.h>
#define close     std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN = 8e5+7;
const ll mod =1e9+7;
const ll inf =0x3f3f3f3f;
const ll INF =0x3f3f3f3f3f3f3f3f;
#define int long long
vector<int> adj[MAXN];
int f[MAXN],deep[MAXN],hson[MAXN],size[MAXN],dfn[MAXN],rak[MAXN],top[MAXN],cnt=0,w[MAXN];
vector<pair<pair<int,int> ,int> > que;
int tree_build(int u,int fa,int dep){
    deep[u]=dep;
    size[u]=1;
    f[u]=fa;
    for(auto &v:adj[u]){
         if(v==fa)continue;
        tree_build(v,u,dep+1);
        size[u]+=size[v];
        if(size[v]>size[hson[u]]||hson[u]==-1) hson[u]=v;
    }
}
//记录所在链的链顶,重边优先遍历的dfs序和dfs序对应的编号
void tree_decomposition(int u,int t){
    top[u]=t;
    cnt++;
    dfn[u]=cnt;
    rak[cnt]=u;
    if(hson[u]!=-1){
        tree_decomposition(hson[u],t);
        for(auto &v:adj[u]){
            if(hson[u]!=v&&v!=f[u]) tree_decomposition(v,v);
        }
    }
}
int a[MAXN];
struct Info {
    int lmin=0,rmin=0,lmax=0,rmax=0,min=0,max=0,sum=0;
};

Info operator + (const Info &a,const Info &b){
    Info c;
    c.sum=a.sum+b.sum;
    c.lmin=min(a.lmin,a.sum+b.lmin);
    c.lmax=max(a.lmax,a.sum+b.lmax);
    c.rmin=min(b.rmin,b.sum+a.rmin);
    c.rmax=max(b.rmax,b.sum+a.rmax);
    c.min=min({a.min,a.rmin+b.lmin,b.min});
    c.max=max({a.max,a.rmax+b.lmax,b.max});
    return c  ;
}
struct node{
    int l,r;
    Info val,lazy;
}seg[MAXN<<2];
void up(int id){
    seg[id].val=seg[id<<1].val+seg[id<<1|1].val;
    //类似状态转移方程 可以更改
}
void build(int id,int l,int r){//建立节点编号为1,维护区间是l-r
    seg[id].l=l;
    seg[id].r=r;
    if(l==r){
        seg[id].val.sum=a[l];
        seg[id].val.lmin=seg[id].val.rmin=min(0LL,a[l]);
        seg[id].val.lmax=seg[id].val.rmax=max(0LL,a[l]);
        seg[id].val.min=min(0LL,a[l]);
        seg[id].val.max=max(0LL,a[l]);
        return;
    }
    int mid=l+r>>1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    up(id);//等处理结束后更新节点信息
}
Info query(int id,int ql,int qr){
    int l=seg[id].l;
    int r=seg[id].r;
    if(ql<=l&&r<=qr) return seg[id].val;
    int mid=l+r>>1;
    if(qr<=mid) return query(id<<1,ql,qr);//只在左儿子
    else if(ql>mid) return query(id<<1|1,ql,qr);//只在右儿子
    else return query(id<<1,ql,qr)+query(id<<1|1,ql,qr);
}
Info rev(Info a){
    Info b=a;
    swap(b.lmax,b.rmax);
    swap(b.lmin,b.rmin);
    return b;
}
void solve(){
    int n;cin>>n;
    int nowCnt=1;
    w[1]=1;
    while(n--){
        char ch;cin>>ch;
        if(ch=='+'){
            int fa,value;
            cin>>fa>>value;
            nowCnt++;
            adj[fa].push_back(nowCnt);
            adj[nowCnt].push_back(fa);
            w[nowCnt]=value;
        }
        else{
            int u,v,w;
            cin>>u>>v>>w;
            que.push_back({{u,v},w});
        }
    }
    for(int i=1;i<=nowCnt;i++) hson[i]=-1; 
    tree_build(1,1,1);
    tree_decomposition(1,1);
    for(int i=1;i<=nowCnt;i++){
        a[dfn[i]]=w[i];
    }
    build(1,1,nowCnt);
    for(auto it:que){
        int u=it.first.first;
        int v=it.first.second;
        int value=it.second;
        Info answer;//ans是最后的信息合并 
        if(deep[u]<deep[v]) swap(u,v);
        Info left,right;
        while(top[u]!=top[v]){//跳重链 
            if(deep[top[u]]>deep[top[v]]){
                left=query(1,min(dfn[top[u]],dfn[u]),max(dfn[top[u]],dfn[u]))+left;
                u=f[top[u]];
            }
            else{
                right=query(1,min(dfn[top[v]],dfn[v]),max(dfn[top[v]],dfn[v]))+right;
                v=f[top[v]];
            }
        }
        if(dfn[u]<=dfn[v])
        right=query(1,min(dfn[u],dfn[v]),max(dfn[u],dfn[v]))+right;
        else 
        left=query(1,min(dfn[u],dfn[v]),max(dfn[u],dfn[v]))+left;
        answer = rev(left)+right;
        if(value>=answer.min&&value<=answer.max) cout<<"YES\n";
        else cout<<"NO\n";
    } 
    for(int i=1;i<=nowCnt;i++){
        adj[i].clear();
        f[i]=0,deep[i]=0,hson[i]=-1,size[i]=0,dfn[i]=0,rak[i]=0,top[i]=0,cnt=0,w[i]=0;
    } 
    cnt=0; 
    que.clear();
    //111
}
signed main(){
    close;
    int t;cin>>t;
    while(t--)
    solve();
}
View Code

 

posted @ 2023-06-21 13:24  xishuiw  阅读(38)  评论(0编辑  收藏  举报