【线段树】【数据结构】NOIP2017列队

本文分享了一种使用线段树解决特定类型问题的方法。通过为每一行和最后一列分别建立线段树,针对不同操作进行高效处理。文章详细解释了如何在遇到操作时更新线段树,并提供了动态加点策略以避免超时和内存溢出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分析:

很简单的线段树水题。。。不知道为啥一年前不会。。。
每行开一个线段树,最后一列再开一个线段树。

对每个操作分两种情况讨论:在最后一列,不在最后一列。

如果在最后一列,那么在线段树上把那个位置删去,然后末尾插入它。

如果不在最后一列,现在行线段树上把那个位置删去,在列线段树末尾插入它。并且找到列线段树对应的行的值,把他从列线段树中删除,加入到行线段树中去。

用动态加点的方式可以避免TLE和MLE

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 15000100
using namespace std;
void Read(int &x){
    char c;	
    while(c=getchar(),c!=EOF&&(c<'0'||c>'9'));
    x=c-'0';
    while(c=getchar(),c!=EOF&&c>='0'&&c<='9')
        x=x*10+c-'0';
}
typedef long long ll;
int n,m,q,cnt;
int tree[MAXN];
ll val[MAXN];
int tag[MAXN];
int ls[MAXN],rs[MAXN];
void pushdown(int x,int l,int r){
    if(tag[x]==0)
        return ;
    if(ls[x]==0)
        ls[x]=++cnt;
    if(rs[x]==0)
        rs[x]=++cnt;
    tag[ls[x]]+=tag[x];
    tag[rs[x]]+=tag[x];
    int mid=(l+r)>>1;
    tree[ls[x]]+=tag[x]*(mid-l+1);
    tree[rs[x]]+=tag[x]*(r-mid);
    tag[x]=0;
}
void add(int id,int l,int r,int pl,int pr,int val){
    if(l!=r)
        pushdown(id,l,r);
    if(l>=pl&&r<=pr){
        tag[id]+=val;	
        tree[id]+=(r-l+1)*val;
        return ;
    }
    int mid=(l+r)>>1;
    if(pl<=mid){
        if(ls[id]==0)
            ls[id]=++cnt;
        add(ls[id],l,mid,pl,pr,val);
    }
    if(pr>mid){
        if(rs[id]==0)
            rs[id]=++cnt;
        add(rs[id],mid+1,r,pl,pr,val);
    }
    tree[id]=tree[ls[id]]+tree[rs[id]];
}
pair<ll,int> que(int id,int l,int r,int k){
    if(l!=r)
        pushdown(id,l,r);
    if(l==r){
        if(val[id]==0)
            return make_pair(l,l);
        else
            return make_pair(val[id],l);
    }
    int mid=(l+r)>>1;
    if(tree[ls[id]]>=k){
        if(ls[id]==0)
            ls[id]=++cnt;
        return que(ls[id],l,mid,k);
    }
    else{
        if(rs[id]==0)
            rs[id]=++cnt;
        return que(rs[id],mid+1,r,k-tree[ls[id]]);
    }
}
void addval(int id,int l,int r,int pos,ll v){
    if(l!=r)
        pushdown(id,l,r);
    if(l==r){
        val[id]=v;
        tree[id]=1;
        tag[id]=0;	
        return ;
    }
    int mid=(l+r)>>1;
    if(pos<=mid){
        if(ls[id]==0)
            ls[id]=++cnt;
        addval(ls[id],l,mid,pos,v);
    }
    else{
        if(rs[id]==0)
            rs[id]=++cnt;
        addval(rs[id],mid+1,r,pos,v);
    }
    tree[id]=tree[ls[id]]+tree[rs[id]];
}
int len[MAXN];
int main(){
    SF("%d%d%d",&n,&m,&q);
    cnt=n+1;
    int l=1,r=m+q-1;
    for(int i=1;i<=n;i++){
        add(i,l,r,1,m-1,1);
        len[i]=m-1;
    }
    add(n+1,1,n+q,1,n,1);
    len[n+1]=n;
    int x,y;
    for(int i=1;i<=q;i++){
        Read(x),Read(y);
        if(y==m){
            pair<ll,int> res=que(n+1,1,n+q,x);
            if(res.second<=n)
                res.first*=m;
            ll delx=res.first;
            PF("%lld\n",delx);
            add(n+1,1,n+q,res.second,res.second,-1);
            len[n+1]++;
            addval(n+1,1,n+q,len[n+1],delx);
        }
        else{
            pair<ll,int> res1=que(x,l,r,y);
            if(res1.second<=m-1)
                res1.first=res1.first+1ll*(x-1)*m;
            ll delx=res1.first;
            PF("%lld\n",delx);
            pair<ll,int> res2=que(n+1,1,n+q,x);
            if(res2.second<=n)
                res2.first*=m;
            ll nx=res2.first;
            add(x,l,r,res1.second,res1.second,-1);
            len[x]++;
            addval(x,l,r,len[x],nx);
            
            add(n+1,1,n+q,res2.second,res2.second,-1);
            len[n+1]++;
            addval(n+1,1,n+q,len[n+1],delx);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值