zoukankan      html  css  js  c++  java
  • 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));
        }
    }
  • 相关阅读:
    聊聊WS-Federation
    用双十一的故事串起碎片的网络协议(上)
    责任链模式的使用-Netty ChannelPipeline和Mina IoFilterChain分析
    最小化局部边际的合并聚类算法(中篇)
    最小化局部边际的合并聚类算法(上篇)
    UVaLive 7371 Triangle (水题,判矩形)
    UVaLive 7372 Excellence (水题,贪心)
    POJ 3312 Mahershalalhashbaz, Nebuchadnezzar, and Billy Bob Benjamin Go to the Regionals (水题,贪心)
    UVa 1252 Twenty Questions (状压DP+记忆化搜索)
    UVa 10817 Headmaster's Headache (状压DP+记忆化搜索)
  • 原文地址:https://www.cnblogs.com/kls123/p/10742300.html
Copyright © 2011-2022 走看看