• ICPC中国南昌国家邀请赛和国际丝绸之路规划大赛预选赛 I J


    I. Max answer

    链接:https://nanti.jisuanke.com/t/38228

    思路:

    枚举最小值,单调栈确定最小值的边界,用线段树+前缀和维护最小值的左右区间

    实现代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    
    const ll M = 5e5+10;
    const ll inf = 1e9;
    ll a[M],Li[M],Ri[M],sum[M];
    ll lmn[M<<2],lmx[M<<2],rmn[M<<2],rmx[M<<2],pre[M],nex[M];
    void build(ll l,ll r,ll rt){
        if(l == r){
            lmn[rt] = nex[l];
            lmx[rt] = nex[l];
            rmn[rt] = pre[l];
            rmx[rt] = pre[l];
            return ;
        }
        ll m = (l + r) >> 1;
        build(lson); build(rson);
        lmn[rt] = min(lmn[rt<<1],lmn[rt<<1|1]);
        rmn[rt] = min(rmn[rt<<1],rmn[rt<<1|1]);
        lmx[rt] = max(lmx[rt<<1],lmx[rt<<1|1]);
        rmx[rt] = max(rmx[rt<<1],rmx[rt<<1|1]);
    }
    
    ll getlmn(ll L,ll R,ll l,ll r,ll rt){
        if(L <= l&&R >= r){
            return lmn[rt];
        }
        ll m = (l + r) >> 1;
        ll ret = inf;
        if(L <= m) ret = min(ret,getlmn(L,R,lson));
        if(R > m) ret = min(ret,getlmn(L,R,rson));
        return ret;
    }
    
    ll getrmn(ll L,ll R,ll l,ll r,ll rt){
        if(L <= l&&R >= r){
            return rmn[rt];
        }
        ll m = (l + r) >> 1;
        ll ret = inf;
        if(L <= m) ret = min(ret,getrmn(L,R,lson));
        if(R > m) ret = min(ret,getrmn(L,R,rson));
        return ret;
    }
    
    ll getlmx(ll L,ll R,ll l,ll r,ll rt){
        if(L <= l&&R >= r){
            return lmx[rt];
        }
        ll m = (l + r) >> 1;
        ll ret = 0;
        if(L <= m) ret = max(ret,getlmx(L,R,lson));
        if(R > m) ret = max(ret,getlmx(L,R,rson));
        return ret;
    }
    
    ll getrmx(ll L,ll R,ll l,ll r,ll rt){
        if(L <= l&&R >= r){
            return rmx[rt];
        }
        ll m = (l + r) >> 1;
        ll ret = 0;
        if(L <= m) ret = max(ret,getrmx(L,R,lson));
        if(R > m) ret = max(ret,getrmx(L,R,rson));
        return ret;
    }
    
    int  main()
    {
        ll n;
        scanf("%lld",&n);ll ans = 0,flag = 0,mid = n+1;
        for(ll i = 1;i <= n;i ++){
            scanf("%lld",&a[i]);
            if(a[i]>0&&flag==0) mid = i,flag = 1;
            ans += a[i]; pre[i] = ans;
        }
        ans = 0;
        for(ll i = n;i >= 1;i --){
            ans += a[i]; nex[i] = ans;
        }
        build(1,n,1);
        stack<ll>s;
        for(ll i = 1;i <= n;i ++){
            while(s.size()&&a[s.top()]>=a[i]) s.pop();
            if(s.empty()) Li[i] = 1;
            else Li[i] = s.top()+1;
            s.push(i);
        }
        while(!s.empty()) s.pop();
        for(ll i = n;i >= 1;i --){
            while(s.size()&&a[s.top()]>=a[i]) s.pop();
            if(s.empty()) Ri[i] = n;
            else Ri[i] = s.top()-1;
            s.push(i);
        }
        while(!s.empty()) s.pop();
        ll cnt = 0,num,mx=0;
        for(ll i = 1;i <= n;i ++){
            if(a[i] >= 0){
                cnt = a[i];
                cnt += getlmx(Li[i],i,1,n,1)-nex[i];
                cnt += getrmx(i,Ri[i],1,n,1)-pre[i];
                mx = max(mx,cnt*a[i]);
                //cout<<cnt<<" "<<getlmx(Li[i],i,1,n,1)<<" "<<getrmx(i,Ri[i],1,n,1)<<endl;
            }
            else{
                cnt = a[i];
                cnt += getlmn(Li[i],i,1,n,1)-nex[i];
                cnt += getrmn(i,Ri[i],1,n,1)-pre[i];
                mx = max(mx,cnt*a[i]);
                 //cout<<cnt<<" "<<getlmn(Li[i],i,1,n,1)-nex[i]<<" "<<getrmn(i,Ri[i],1,n,1)-pre[i]<<endl;
            }
           //cout<<a[i]<<" "<<Li[i]<<" "<<Ri[i]<<" "<<mx<<endl;
        }
        printf("%lld
    ",mx);
    }

    J. Distance on the tree

    链接:https://nanti.jisuanke.com/t/38229

    思路;

    序列上求任意区间有多少个数小于k

    https://www.cnblogs.com/kls123/p/9568553.html

    就是这道题扔到树上,一开始想复杂了,还以为是点对的数量。

    从根节点向下遍历每次遍历到一条边看作是一次修改,下标为val的点+1

    但是这种方法建的主席树是类似权值线段树的,下标和树是没关系的,有关系的是这是第几次修改的,所以在树上应该用root跳

    注意 在树上跳的时候表示当前点前后的点时应该用fa[],son[],而不是+1,-1.

    实现代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int M = 3e5+10;
    int ls[M*40],rs[M*40],sum[M*40],a[M],b[M],root[M];
    int cnt1,cnt,head[M],dep[M],siz[M],fa[M],son[M],wt[M],top[M],tid[M],rk[M];
    int idx,tot;
    struct node{
        int w,to,next;
    }e[M*2];
    
    void add(int u,int v,int c){
        e[++cnt1].to=v;e[cnt1].next=head[u];e[cnt1].w=c;head[u]=cnt1;
        e[++cnt1].to=u;e[cnt1].next=head[v];e[cnt1].w=c;head[v]=cnt1;
    }
    void dfs1(int u,int faz,int deep){
        dep[u] = deep;
        siz[u] = 1;
        fa[u] = faz;
        for(int i = head[u];i ;i=e[i].next){
            int v = e[i].to;
            if(v != fa[u]){
                wt[v] = e[i].w;
                dfs1(v,u,deep+1);
                siz[u] += siz[v];
                if(son[u]==-1||siz[v]>siz[son[u]])
                    son[u] = v;
            }
        }
    }
    
    void dfs2(int u,int t){
        top[u] = t;
        tid[u] = tot;
        rk[tot] = wt[u];
        //cout<<1<<endl;
        tot++;
        if(son[u] == -1) return ;
        dfs2(son[u],t);
        for(int i = head[u];i;i=e[i].next){
            int v = e[i].to;
            if(v != son[u]&&v != fa[u])
                dfs2(v,v);
        }
    }
    
    void update(int old,int &k,int l,int r,int p){
        k = ++idx;
        ls[k] = ls[old]; rs[k] = rs[old];
        sum[k] = sum[old] + 1;
        if(l == r) return ;
        int mid = (l + r) >> 1;
        if(p <= mid) update(ls[old],ls[k],l,mid,p);
        else update(rs[old],rs[k],mid+1,r,p);
    }
    
    int query(int old,int k,int L,int R,int l,int r){
        if(L <= l&&R >= r) return sum[k] - sum[old];
        int mid = (l + r) >> 1;
        int ret = 0;
        if(L <= mid) ret += query(ls[old],ls[k],L,R,l,mid);
        if(R > mid) ret += query(rs[old],rs[k],L,R,mid+1,r);
        return ret;
    }
    
    int ask(int x,int y,int l,int r){
        int ans = 0;
        int fx = top[x],fy = top[y];
        while(fx != fy){
            if(dep[fx] < dep[fy]) swap(fx,fy),swap(x,y);
            if(fx == 1) ans += query(root[tid[fx]],root[tid[x]],l,r,1,cnt);
            else ans += query(root[tid[fa[fx]]],root[tid[x]],l,r,1,cnt);
            x = fa[fx]; fx = top[x];
        }
        if(x==y) return ans; 
        if(dep[x] > dep[y]) swap(x,y);
        ans += query(root[tid[x]],root[tid[y]],l,r,1,cnt);
        return ans;
    }
    
    void dfs(int u,int fa){
        update(root[tid[fa]],root[tid[u]],1,cnt,wt[u]);
        for(int i = head[u];i;i=e[i].next){
            int v = e[i].to;
            if(v == fa) continue;
            dfs(v,u);
        }
    }
    
    int l[M],r[M],x[M],u[M],v[M],w[M];
    int Find(int x){
        int num = lower_bound(b+1,b+1+cnt,x)-b;
        return num;
    }
    
    int main()
    {
        int m,n;
        scanf("%d%d",&n,&m); tot = 1;
        memset(son,-1,sizeof(son));
        for(int i = 1;i < n;i ++){
            scanf("%d%d%d",&u[i],&v[i],&w[i]);
            b[i] = w[i];
        }
        for(int i = 1;i <= m;i ++){
            scanf("%d%d%d",&l[i],&r[i],&x[i]);
            b[i+n-1] = x[i];
        }
        sort(b+1,b+n+m);
        cnt = unique(b+1,b+n+m)-b;
        for(int i = 1;i < n;i ++){
            int num = Find(w[i]);
            add(u[i],v[i],num);
        }
        dfs1(1,0,1); dfs2(1,1);dfs(1,0);
        for(int i = 1;i <= m;i ++){
            int num = Find(x[i]);
            printf("%d
    ",ask(l[i],r[i],1,num));
        }
    }
  • 相关阅读:
    LeetCode:204. 计数质数
    LeetCode:203. 移除链表元素
    LeetCode:202. 快乐数
    LeetCode:191. 位1的个数
    LeetCode:190. 颠倒二进制位
    LeetCode:189. 旋转数组
    LeetCode:187. 重复的DNA序列
    LeetCode:165. 比较版本号
    LeetCode:164. 最大间距
    LeetCode:155. 最小栈
  • 原文地址:https://www.cnblogs.com/kls123/p/10742300.html
Copyright © 2020-2023  润新知