• 数据结构总结


    数据结构总结

    • 堆(优先队列)

      黑匣子

      开一个大根堆,一个小根堆,保证大根堆的元素个数为查询的i-1,输出小根堆的堆顶即可。如果插入的数a[j]比大根堆堆顶小,则把大根堆堆顶放到小根堆,a[j]放到大根堆里,保证大根堆里的最大值小于小根堆里的最小值。查询时把小根堆的堆顶放到大根堆里,使大根堆元素个数+1。

    code:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=200010;
    priority_queue<int>qmax;
    priority_queue<int,vector<int>,greater<int> >qmin;
    int m,n;
    int a[N],u[N];
    int main()
    {
        scanf("%d%d",&m,&n);
        int j=0;
        for(int i=1;i<=m;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)scanf("%d",&u[i]);
        for(int i=1;i<=n;i++)
        {
            while(j<u[i])
            {
                j++;
                if(!qmax.size()||a[j]>qmax.top())
                {
                    qmin.push(a[j]);
                }
                if(qmax.size()&&a[j]<qmax.top())
                {
                    qmin.push(qmax.top());
                    qmax.pop();qmax.push(a[j]);
                }
            }printf("%d
    ",qmin.top());
            qmax.push(qmin.top());qmin.pop();
        }
    }
    • 线段树

      P2824排序

      直接做会觉得无从下手,我们考虑二分一个排名k,把比k小的数变成0,>=k的变成1,这样判断查找的pos值是0还是1,如果是1,说明二分的排名小了,否则说明排名大了,check用线段树维护区间1的个数,并支持覆盖(染色)和查询操作。

    code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define lch (now<<1)
    #define rch (now<<1|1)
    #define smid  ((l+r)>>1)
    using namespace std;
    const int N=1e5+10;
    
    struct node
    {
        int l,r,cover,sum;
    }sgt[N<<2];
    
    int n,m,pos;
    int b[N];
    struct Q
    {
        int cid,l,r;
    }q[N];
    
    void pushup(int now)
    {
        sgt[now].sum=sgt[lch].sum+sgt[rch].sum;
    }    
    
    void bt(int now,int l,int r,int x)
    {
        sgt[now].cover=-1;
        if(l==r)
        {
            sgt[now].sum=b[l]>=x;return;
        }
        bt(lch,l,smid,x);
        bt(rch,smid+1,r,x);
        pushup(now);
    }
    
    void pushdown(int now,int l,int r)
    {
        if(sgt[now].cover==-1)return;
        sgt[lch].cover=sgt[rch].cover=sgt[now].cover;
        if(sgt[now].cover==1)sgt[lch].sum=(smid-l+1),sgt[rch].sum=(r-smid);
        else sgt[lch].sum=sgt[rch].sum=0;
        sgt[now].cover=-1;
    }
    
    int query(int now,int l,int r,int x,int y)
    {
        if(x<=l&&r<=y)return sgt[now].sum;
        if(x>r||y<l)return 0;
        pushdown(now,l,r);
        int res=0;
        res+=query(lch,l,smid,x,y);
        res+=query(rch,smid+1,r,x,y);
        return res;
    }
    
    void modify(int now,int l,int r,int x,int y,int val)
    {
        if(x<=l&&r<=y)
        {
            if(val==1)sgt[now].sum=(r-l+1),sgt[now].cover=1;
            else sgt[now].sum=0,sgt[now].cover=0;
            return;
        }
        if(x>r||y<l)return;
        pushdown(now,l,r);
        modify(lch,l,smid,x,y,val);
        modify(rch,smid+1,r,x,y,val);
        pushup(now);
    }    
    
    bool check(int mid)
    {
        bt(1,1,n,mid);
        
        for(int i=1;i<=m;i++)
        {
            int res=query(1,1,n,q[i].l,q[i].r);
            if(q[i].cid==0)
            {
                modify(1,1,n,q[i].r-res+1,q[i].r,1);
                modify(1,1,n,q[i].l,q[i].r-res,0);
            }
            else 
            {
                modify(1,1,n,q[i].l,q[i].l+res-1,1);
                modify(1,1,n,q[i].l+res,q[i].r,0);
            }
        }
        if(query(1,1,n,pos,pos)==1)return 1;
        return 0;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        scanf("%d",&b[i]);
        for(int i=1;i<=m;i++)
        scanf("%d%d%d",&q[i].cid,&q[i].l,&q[i].r);
        scanf("%d",&pos);
        int L=0,R=N;
        while(L<R-1)
        {
            int mid=((L+R)>>1);
            if(check(mid))L=mid;
            else R=mid;
        }
        printf("%d",L);
    }
    • 树状数组(Binary Indexed Tree)

      P5094MooFest

      

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define go(i,a,b) for(int i=a;i<=b;i++)
    #define lowbit(x) (x&-x)
    #define LL long long 
    using namespace std;
    const int N=20010;
    struct COW
    {
        int v,x;
    }c[N];
    int n;
    LL tot,ans;
    LL bit1[N],bit2[N];
    
    bool cmp(COW a,COW b)
    {
        return a.v<b.v;
    }
    
    int query_bit1(int pos)
    {
        int res=0;
        while(pos)
        {
            res+=bit1[pos];
            pos-=lowbit(pos);
        }return res;
    }
    
    int query_bit2(int pos)
    {
        int res=0;
        while(pos)
        {
            res+=bit2[pos];
            pos-=lowbit(pos);
        }return res;
    }
    
    void add_bit1(int pos,int val)
    {
        while(pos<=N)
        {
            bit1[pos]+=val;
            pos+=lowbit(pos);
        }
    }
    
    void add_bit2(int pos,int val)
    {
        while(pos<=N)
        {
            bit2[pos]+=val;
            pos+=lowbit(pos);
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        go(i,1,n)
        scanf("%d%d",&c[i].v,&c[i].x);
        sort(c+1,c+1+n,cmp);//按v排序,这样可以不用比max 
        for(int i=1;i<=n;i++)//bit1维护比x[i]小的个数,bit2维护比x[i]小的x[j]的和 
        {
            LL num=query_bit1(c[i].x);//
            LL sum=query_bit2(c[i].x);
            ans+=c[i].v*(num*c[i].x-sum);
            ans+=c[i].v*((tot-sum)-(i-1-num)*c[i].x);
            tot+=c[i].x;
            add_bit1(c[i].x,1);
            add_bit2(c[i].x,c[i].x);
        }
        printf("%lld",ans);
    }
        
    •  并查集

      SP5150 JMFILTER - Junk-Mail Filter

      merge和find操作没什么不同。难点在删除操作。

      我们给0->n-1的每个点的父亲赋为n->n*2-1,相当于一个虚拟父亲。这样我们在0->n-1元素中合并时,根节点始终在n->n*2-1,我们在从并查集中删除节点时,直接把其父亲赋为n*2->m中的元素,这样和它在同一个集合里的元素根在n->n*2-1中,它可以直接删除。

    code:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1e5+10;
    const int M=1e6+10;
    int father[2*N+M];
    bool vis[2*N+M];
    int n,m,tmp;
    
    int find(int x)
    {
        if(x==father[x])return  x;
        return father[x]=find(father[x]);
    }
    
    int main()
    {
        int T=0;
        while(1)
        {
            scanf("%d%d",&n,&m);
            if(!n&&!m)return 0;
            tmp=n<<1;T++;
            for(int i=0;i<n;i++)father[i]=i+n;
            for(int i=n;i<tmp+m;i++)father[i]=i;
            char opt;memset(vis,0,sizeof(vis));
            while(m--)
            {
                cin>>opt;
                if(opt=='M')
                {
                    int x,y;scanf("%d%d",&x,&y);
                    int r1=find(x),r2=find(y);
                    father[r1]=r2;
                }
                if(opt=='S')
                {
                    int x;scanf("%d",&x);
                    father[x]=tmp++;
                }
            }int ans=0;
            for(int i=0;i<n;i++)
            {
                int r=find(i);if(!vis[r])ans++,vis[r]=1;
            }
            printf("Case #%d: %d
    ",T,ans);
        }
    }
            
  • 相关阅读:
    汇编笔记
    【BZOJ 1701】Cow School(斜率优化/动态凸包/分治优化)
    MS-DOS 6.22 +Vim+masm 汇编环境
    「NOIP2017」时间复杂度
    CCF 201809-3 元素选择器
    CCF 201712-3 Crontab
    ICPC NWERC2019~2020 Practice Contest
    蓝桥杯模拟赛3 F:等差等比有联系 公差公比求通项
    CCF 201509-3 模板生成系统
    CCF 201503-3 节日
  • 原文地址:https://www.cnblogs.com/THRANDUil/p/11062010.html
Copyright © 2020-2023  润新知