数据结构总结

数据结构总结

  • 堆(优先队列)

  黑匣子

 

  开一个大根堆,一个小根堆,保证大根堆的元素个数为查询的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\n",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\n",T,ans);
    }
}
        

 

转载于:https://www.cnblogs.com/THRANDUil/p/11062010.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值