• 2018 UESTC Training for Data Structures


    Link


    A - 一棵简单的线段树

    标准线段树

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int maxn = 1e6+7;
    
    int n,q;
    struct node
    {
        int l,r,maxx,minx;
        ll num;
        ll sum;
    }t[maxn*4];
    
    void build(int x,int l,int r)
    {
        t[x].l=l,t[x].r=r;
        if(l==r)
        {
            t[x].num=t[x].maxx=t[x].minx=t[x].sum=0;
            return;
        }
        int mid=(l+r)/2;
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
        t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
        t[x].maxx=max(t[x<<1].maxx,t[x<<1|1].maxx);
        t[x].minx=min(t[x<<1].minx,t[x<<1|1].minx);
    }
    
    void update(int x,int p,int val)
    {
        int l=t[x].l,r=t[x].r;
        if(l==r && l==p){
            t[x].num=t[x].sum=t[x].minx=t[x].maxx=val;
            return;
        }
        int mid=(l+r)/2;
        if(p<=mid) update(x<<1,p,val);
        else update(x<<1|1,p,val);
        t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
        t[x].maxx=max(t[x<<1].maxx,t[x<<1|1].maxx);
        t[x].minx=min(t[x<<1].minx,t[x<<1|1].minx);
    }
    
    ll query(int x,int ql,int qr)
    {
    
        int l=t[x].l,r=t[x].r;
        if(ql<=l && qr>=r)
        {
            return t[x].sum;
        }
        int mid=(l+r)/2;
        ll ans=0;
        if(qr>mid)  ans+=query(x<<1|1,ql,qr);
        if(ql<=mid) ans+=query(x<<1,ql,qr);
        return ans;
    }
    
    int querymax(int x,int ql,int qr)
    {
        int l=t[x].l,r=t[x].r;
        if(ql<=l && qr>=r)
        {
            return t[x].maxx;
        }
        int mid=(l+r)/2;
        int ans=-1e9-2;
        if(qr>mid)  ans=max(ans,querymax(x<<1|1,ql,qr));
        if(ql<=mid) ans=max(ans,querymax(x<<1,ql,qr));
        return ans;
    }
    
    int querymin(int x,int ql,int qr)
    {
        int l=t[x].l,r=t[x].r;
        if(ql<=l && qr>=r)
        {
            return t[x].minx;
        }
        int mid=(l+r)/2;
        int ans=1e9+2;
        if(qr>mid)  ans=min(ans,querymin(x<<1|1,ql,qr));
        if(ql<=mid) ans=min(ans,querymin(x<<1,ql,qr));
        return ans;
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&q)!=EOF)
        {
        build(1,1,n);
        while(q--)
        {
            int type,l,r,p,x;
            scanf("%d",&type);
            if(type==0)
            {
                scanf("%d%d",&p,&x);
                update(1,p,x);
            }
            else
            {
                scanf("%d%d",&l,&r);
                ll ans=query(1,l,r);
                ll maxx=querymax(1,l,r);
                ll minx=querymin(1,l,r);
                //cout<<ans<<' '<<maxx<<' '<<minx<<endl;
                printf("%lld
    ", ans-maxx-minx);
            }
        }
        }
        return 0;
    }

    B - 一棵普通的线段树

    线段树+Lazy标记

    记得要将Lazy   push_up和push_down


    C - 一棵像样的线段树

    题意

    设 xem 表示集合中最小的未出现的正整数, 如 xem{}=1xem{1,3,4}=2.

    定义   bi=xem{bici,bici+1,...,bi1},i=1,2,...,n    特别的,b0=1b.        给定 n 和 c1,c2,...,cn,请你计算出 b1,b2,...,bn.         (n<=1e6)

    第一行一个n,第二行c1,c2.........cn  (1<=ci<=i)

    输出n个数依次为b1,b2,b3......bn

    分析


    D - 一棵复杂的线段树

    题意

    给出了一个数组 A[1..n], 初始元素为 a1,a2,...,an 是 1n 的一个排列. 然后对数组施以了 m 个操作. 每个操作针对一个区间 [l,r] (1lrn),将区间内的元素从小到大排序或者从大到小排序.

    给出n,k,m,有m条操作,给出三个数o,l,r,o=0,代表区间[l,r]从小到大排序,o=1,从大到小,输出最终的第k个数即A[k]          ( n(1n105) 和 k(1kn) )

    分析

    由于数为1~n且我们只求第k个元素,故只关注第k个元素

    二分答案即最后第k个数,首先将所有大于mid的设为1,小与等于的为0,每次对区间排序操作相当于改变区间内的0和1的顺序,比如:设区间[l,r]中1的数量为c,① 对区间[l,r]进行升序操作,相当于将区间[l,r]全部设为0后,将最后c个设为1,即[L,R-c+1], ② 对区间[l,r]进行升序操作时,反之 。所有操作后,由于我们一开始将答案所在的数设为0,最后一个是的[k,k]区间为0的即为答案

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int maxn = 1e5+7;
    
    int a[maxn];
    int type[maxn],ql[maxn],qr[maxn];
    
    struct node
    {
        int l,r,sum;
        int lazy;
    }t[maxn*4];
    
    void build(int x,int l,int r,int mid)
    {
        t[x].l=l,t[x].r=r;
        t[x].lazy=-1;
        if(l==r){
    
            if(a[l]>mid)
                t[x].sum=1;
            else
                t[x].sum=0;
            return;
        }
        int m=(l+r)/2;
        build(x<<1,l,m,mid);
        build(x<<1|1,m+1,r,mid);
        t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
    }
    
    void update(int x,int ql,int qr,int val){
    
        int l=t[x].l, r=t[x].r;
        if(ql<=l && qr>=r){
            t[x].sum=(r-l+1)*val;
            t[x].lazy=val;
            return;
        }
        if(t[x].lazy!=-1){
            t[x<<1].lazy=t[x].lazy;
            t[x<<1|1].lazy=t[x].lazy;
            t[x<<1].sum=(t[x<<1].r-t[x<<1].l+1)*t[x].lazy;
            t[x<<1|1].sum=(t[x<<1|1].r-t[x<<1|1].l+1)*t[x].lazy;
            t[x].lazy=-1;
        }
        int mid=(l+r)/2;
        if(qr>mid) update(x<<1|1,ql,qr,val);
        if(ql<=mid) update(x<<1,ql,qr,val);
        t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
    }
    
    int query(int x,int ql,int qr)
    {
        int l=t[x].l,r=t[x].r;
        if(ql<=l && qr>=r){
            return t[x].sum;
        }
        if(t[x].lazy!=-1){
            t[x<<1].lazy=t[x].lazy;
            t[x<<1|1].lazy=t[x].lazy;
            t[x<<1].sum=(t[x<<1].r-t[x<<1].l+1)*t[x].lazy;
            t[x<<1|1].sum=(t[x<<1|1].r-t[x<<1|1].l+1)*t[x].lazy;
            t[x].lazy=-1;
        }
        int mid=(l+r)/2;
        int ans=0;
        if(qr>mid)  ans+=query(x<<1|1,ql,qr);
        if(ql<=mid) ans+=query(x<<1,ql,qr);
        t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
        return ans;
    }
    int main()
    {
        int n,k,m;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d%d", &type[i], &ql[i], &qr[i]);
        }
        int l=1,r=n;
        while(l<r){
            int mid=(l+r)/2;
            build(1,1,n,mid);
            for(int i=1;i<=m;i++){
                int num=query(1,ql[i],qr[i]);
                update(1,ql[i],qr[i],0);
                if(type[i]){
                    update(1,ql[i],ql[i]+num-1,1);
                }
                else{
                    update(1,qr[i]-num+1,qr[i],1);
                }
            }
            if(query(1,k,k)){
                l=mid+1;
            }
            else
                r=mid;
        }
        printf("%d
    ",l);
        return 0;
    }

    E - 小埋的steam愿望单

    题意

    小埋有一个steam愿望单,上面记载着她想买的游戏!现在小埋有以下 n 个操作:

    1 x y 添加一个价格为 y 名字为 x 的游戏加入愿望单

    2 x 删除名字为 x 的游戏

    3 x y 名字为 x 的游戏价格调整为 y

    4 x 为 1 输出最便宜的游戏的名字(如果有多个同价格游戏输出字典序最小的),x 为 2 输出最贵的游戏(如果有多个同价格游戏输出字典序最大的)        ( n<=1e5 )

    不合法的情况请忽略该操作

    分析

    STL Set,set支持begin、end、erase等操作,用set按题意模拟即可,对于可能的无效操作,map哈希判断一下存在不存在即可


    F - 好吃不饺子

    题意

    饺子发现身边危机四伏!有n个人站在一维平面上,每个人的坐标为Ai,能量值为Bi。饺子有c种方法可以推测出有多少人想吃饺子,请你求出每种方法可以得出的想吃饺子的人数

    第一行两个值 nn105)c(c10)
    接下来n行每行两个值Ai,Bi(1Ai109,1Bi104,AiAAi,Bi i<j)
    接下来c行,每行包含三个数K,function,length
    其中
    K可能为gt或者lt,代表大于或者小于
    function可能为minmax或者avg,代表最小,最大或者平均
    lengthl是一个整数(1length1e9)
    K,function,length的意思为对于第i号人,如果BK于[Ailength,Ai)范围内的所有人能量值的function值,说明该人想吃饺子,特别的如果范围内一个人也没有,则这个人不想吃饺子

    分析

    由于Ai的数据范围,刚开始我考虑以Ai值为叶子节点动态建树,然后查询即可,实现起来有点麻烦,原因:找错了建树的区间

    一直wa2,还没改过去

    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long  ll;
    const int maxn = 1e5+7;
    
    int n,c,A[maxn],B[maxn],cnt;
    
    struct node{
        int l,r,lson,rson,b,maxx,minx,sum,num;
    }t[maxn*40];
    int root;
    
    
    int newnode()
    {
        ++cnt;
        return cnt;
    }
    
    void build(int &x,int l ,int r,int p,int val){
        if(!x) x=newnode();
        t[x].l=l,t[x].r=r;
        t[x].num++;
        if(l==r)
        {
            t[x].sum+=val;
            t[x].maxx=max(t[x].maxx,val);
            if(!t[x].minx) t[x].minx=val;
            else t[x].minx=min(t[x].minx,val);
            return;
        }
        int mid=(l+r)/2;
        if(p<=mid) build(t[x].lson,l,mid,p,val);
        else build(t[x].rson,mid+1,r,p,val);
        t[x].sum=t[t[x].lson].sum+t[t[x].rson].sum;
        t[x].maxx=max(t[t[x].lson].maxx,t[t[x].rson].maxx);
        if(!t[t[x].lson].minx)t[x].minx=t[t[x].rson].minx;
        else if(!t[t[x].rson].minx) t[x].minx=t[t[x].lson].minx;
        else t[x].minx=min(t[t[x].lson].minx,t[t[x].rson].minx);
        return;
    }
    
    int querymax(int x,int ql,int qr)
    {
        int l=t[x].l,r=t[x].r;
        if(ql<=l && qr>=r)
            return t[x].maxx;
        int mid=(l+r)/2;
        int ans=0;
        if(qr>mid)
        {
            if(t[x].rson) ans=max(ans,querymax(t[x].rson,ql,qr));
        }
        if(ql<=mid)
        {
            if(t[x].lson) ans=max(ans,querymax(t[x].lson,ql,qr));
        }
        return ans;
    }
    
    int querymin(int x,int ql,int qr)
    {
        int l=t[x].l,r=t[x].r;
        if(ql<=l && qr>=r)
            return t[x].minx;
        int mid=(l+r)/2;
        int ans=1e9+5;
        if(qr>mid)
        {
            if(t[x].rson) ans=min(ans,querymin(t[x].rson,ql,qr));
        }
        if(ql<=mid)
        {
            if(t[x].lson) ans=min(ans,querymin(t[x].lson,ql,qr));
        }
        return ans;
    }
    
    ll querysum(int x,int ql,int qr)
    {
        int l=t[x].l,r=t[x].r;
        if(ql<=l && qr>=r)
            return t[x].sum;
        int mid=(l+r)/2;
        ll ans=0;
        if(qr>mid)
        {
            if(t[x].rson)ans+=1LL*querysum(t[x].rson,ql,qr);
        }
        if(ql<=mid)
        {
            if(t[x].lson)ans+=1LL*querysum(t[x].lson,ql,qr);
        }
        return ans;
    }
    
    int querynum(int x,int ql,int qr)
    {
        int l=t[x].l,r=t[x].r;
        if(ql<=l && qr>=r)
            return t[x].num;
        int mid=(l+r)/2;
        ll ans=0;
        if(qr>mid)
        {
            if(t[x].rson)ans+=1LL*querynum(t[x].rson,ql,qr);
        }
        if(ql<=mid) {
            if(t[x].lson)ans+=1LL*querynum(t[x].lson,ql,qr);
        }
        return ans;
    }
    
    
    
    int main()
    {
        scanf("%d%d",&n,&c);
        for(int i=1;i<=n;i++) scanf("%d%d",&A[i],&B[i]),build(root,1,1e9,A[i],B[i]);
    
        while(c--)
        {
            char k[10],f[10];
            int len;
            scanf("%s%s%d",&k,&f,&len);
            ll cnt=0;
            if(k[0]=='g')
            {
                if(f[2]=='n')
                {
                    for(int i=2;i<=n;i++)
                    {
                       int lz=max(1,A[i]-len);
                       if(lz >= A[i]) continue;
                       ll kk=querymin(root,lz,A[i]-1);
                       if(B[i]>kk && kk && kk!=(1e9 + 5))
                        cnt++;
                    }
                }
                else if(f[2]=='x')
                {
                    for(int i=2;i<=n;i++)
                    {
                       int lz=max(1,A[i]-len);
                       if(lz >= A[i]) continue;
                       ll kk=querymax(root,lz,A[i]-1);
                       if(B[i]>kk&&kk)
                        cnt++;
                    }
                }
                else
                {
                    for(int i=2;i<=n;i++)
                    {
                       int lz=max(1,A[i]-len);
                       if(lz >= A[i]) continue;
                       double kk=(1.0*querysum(root,lz,A[i]-1))/(querynum(root,lz,A[i]-1));
                       if(B[i]>kk && kk)
                        cnt++;
                    }
                }
            }
            else
            {
                if(f[2]=='n')
                {
                    for(int i=2;i<=n;i++)
                    {
                       int lz=max(1,A[i]-len);
                       if(lz >= A[i]) continue;
                       ll kk=querymin(root,lz,A[i]-1);
                       if(B[i]<kk && kk && kk!=(1e9 + 5))
                        cnt++;
                    }
                }
                else if(f[2]=='x')
                {
                    for(int i=2;i<=n;i++)
                    {
                       int lz=max(1,A[i]-len);
                       if(lz >= A[i]) continue;
                       ll kk=querymax(root,lz,A[i]-1);
                       if(B[i]<kk && kk)
                        cnt++;
                    }
                }
                else
                {
                    for(int i=2;i<=n;i++)
                    {
                       int lz=max(1,A[i]-len);
                       if(lz <= A[i]) continue;
                       double kk=(1.0*querysum(root,lz,A[i]-1))/(querynum(root,lz,A[i]-1));
                       if(B[i]<kk && kk)
                        cnt++;
                    }
                }
            }
            printf("%lld
    ",cnt);
        }
        return 0;
    }

    实际上无需动态建树,由于Ai是非递减的,考虑以Bi为叶子节点建树,1~n每个节点代表Bi即可,对于每个询问二分得到查询区间的左边界,线段树查询即可

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <iostream>
    #define ll long long
    using namespace std;
    const int MaxN=100010;
    const double INF=1e9;
    struct part{
    double maxx;
    double min;
    double sum;
    };
    ll n,c,ans,i,j;
    double a[100010],b[100010],length,v;
    char func[100],k[100];
    struct part s[MaxN*4];
    
    void pushup(ll rt)
    {
        s[rt].sum=s[rt*2].sum+s[rt*2+1].sum;
        s[rt].max=max(s[rt*2].max,s[rt*2+1].max);
        s[rt].min=min(s[rt*2].min,s[rt*2+1].min);
    }
    
    void build(ll rt,ll l,ll r)
    {
        if (l==r)
        {
            s[rt].sum=s[rt].max=s[rt].min=b[l];
            return;
        }
        ll mid=(l+r)/2;
        build(rt*2,l,mid);
        build(rt*2+1,mid+1,r);
        pushup(rt);
    }
    
    double findsum(ll rt,ll l,ll r,ll L,ll R)
    {
        double ans;
    if (L<=l&&r<=R)
    {
        return(s[rt].sum);
    }
    ll mid=(l+r)/2;
    ans=0;
    if (L<=mid) ans+=findsum(rt*2,l,mid,L,R);
    if (R>mid) ans+=findsum(rt*2+1,mid+1,r,L,R);
    return(ans);
    }
    
    double findmax(ll rt,ll l,ll r,ll L,ll R)
    {
        double ans;
    if (L<=l&&r<=R)
    {
        return(s[rt].max);
    }
    ll mid=(l+r)/2;
    ans=-INF;
    if (L<=mid) ans=max(ans,findmax(rt*2,l,mid,L,R));
    if (R>mid) ans=max(ans,findmax(rt*2+1,mid+1,r,L,R));
    return(ans);
    }
    
    double findmin(ll rt,ll l,ll r,ll L,ll R)
    {
    double ans;
    if (L<=l&&r<=R)
    {
        return(s[rt].min);
    }
    ll mid=(l+r)/2;
    ans=INF;
    if (L<=mid) ans=min(ans,findmin(rt*2,l,mid,L,R));
    if (R>mid) ans=min(ans,findmin(rt*2+1,mid+1,r,L,R));
    return(ans);
    }
    
    int main()
    {
        scanf("%lld%lld",&n,&c);
        for (i=1;i<=n;i++)
        scanf("%lf%lf",&a[i],&b[i]);
        build(1,1,n);
        for (i=1;i<=c;i++)
        {
            cin>>k>>func>>length;
            ans=0;
            for (j=1;j<=n;j++)
            {
                ll l=lower_bound(a+1,a+n+1,a[j]-length)-a;
                ll r=j;
                while (r>0&&a[r]==a[r-1]) r--;
                r--;
                if (l<=r)
                {
                    if (strcmp(func,"avg")==0) v=findsum(1,1,n,l,r)/(r-l+1); else
                    if (strcmp(func,"max")==0) v=findmax(1,1,n,l,r); else
                    if (strcmp(func,"min")==0) v=findmin(1,1,n,l,r);
                    if ((b[j]>v&&strcmp(k,"gt")==0)||(b[j]<v&&strcmp(k,"lt")==0)) ans++;
                }
            }
           printf("%lld
    ",ans);
    
        }
        return(0);
    }

    G - 三澄美琴的心里只有学习

    题意

    分析


    H - 中堂系的困难任务

    题意

    分析


    I - 不如把并查集加上个计数功能吧

    题意

    分析


    J - 老头马桶枪!

    题意

    分析


    K - 爱吃瓜的伊卡洛斯(1)

    题意

    分析


    L - 爱吃瓜的伊卡洛斯(2)

    题意

    分析


    M - 一道普通题1

    题意

    分析


    N - 一道普通的题2

    题意

    分析


    O - 帆宝RMQ

    题意

    分析


    P - 为什么你这么熟练啊

    题意

    分析


    Q - 这是一道简单题

    题意

    分析


    Summary:

  • 相关阅读:
    JavaScript
    格式与布局
    表单和样式表
    HTML中表格的使用
    HTML 基础
    foreach使用和函数
    20160423 二维数组,锯齿数组和集合
    【学习笔记】系统集成项目管理
    BSEG和BSIS、BSAS、BSID、BSAD、BSIK、BSAK六个表的关系(转)
    关于ABAP事件的一张图
  • 原文地址:https://www.cnblogs.com/Deadline/p/9003498.html
Copyright © 2020-2023  润新知