码迷,mamicode.com
首页 > 其他好文 > 详细

线段树单点更新解插空问题

时间:2018-11-03 02:12:37      阅读:185      评论:0      收藏:0      [点我收藏+]

标签:algorithm   int   等价   插入   string   pre   size   fine   sizeof   

poj2828

线段树维护区间空余的位置,每次插入一个点

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define maxn 200020
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
struct node{
    int pos,w,id;
}nodes[maxn];
int sum[maxn<<2];
int ans[maxn];//用来存储
void pushUP(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt){
    if(l==r){
        sum[rt]=1;
        return;
    }
    int m=l+r>>1;
    build(lson);
    build(rson);
    pushUP(rt);
}
void update(int i,int pos,int l,int r,int rt){
    if(l==r){
        ans[l]=nodes[i].w;
        sum[rt]--;
        return;
    }
    sum[rt]--;
    int m=l+r>>1;
    if(pos<=sum[rt<<1])
        update(i,pos,lson);
    else 
        update(i,pos-sum[rt<<1],rson);
}
int main(){
    int n;
    while(scanf("%d",&n)==1){
        memset(ans,0,sizeof ans);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&nodes[i].pos,&nodes[i].w),nodes[i].pos++;
        build(1,n,1);
        for(int i=n;i>=1;i--)
            update(i,nodes[i].pos,1,n,1);//倒着把i个插队更新到线段树里
        for(int i=1;i<=n;i++)
            printf("%d ",ans[i]);
        puts("");
    }
}

hdu3564 线段树解决插值,求出最终序列,再求lis

/*
给出n个数字,依次分别是[1,n]
每次给定第i个数字的插入点【0,n-1],求lis

离线+线段树+lis
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 1000005
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define inf 0x3f3f3f3f
int sum[maxn<<2];//存储当前位置有多少空位
int ans[maxn];//ans[i]表示i在位置ans[i]
int op[maxn];
int dp[maxn];
void build(int l,int r,int rt){
    if(l==r){
        sum[rt]=1;
        return;
    }
    int m=l+r>>1;
    build(lson);
    build(rson);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int pos,int val,int l,int r,int rt){
    if(l==r){
        sum[pos]=0;
        ans[val]=l;//val被放在了位置l
        return;
    }
    sum[pos]--;
    int m=l+r>>1;
    if(pos<=sum[rt<<1]) update(pos,val,lson);
    else update(pos-sum[rt<<1],val,rson);
}
int main(){
    int n,T;
    cin >> T;
    for(int tt=1;tt<=T;tt++){
        memset(sum,0,sizeof sum);
        memset(ans,0,sizeof ans);
        memset(op,0,sizeof op);
        
        printf("Case #%d:\n",tt);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&op[i]),op[i]++;
        build(1,n,1);//从0开始建立线段树
        for(int i=n;i>=1;i--)
            update(op[i],i,1,n,1);//把i插到op[i]及其以后位置,ans[i]维护i的位置
        
        //第一次插入1,第二次插入2,第三次插入3...其位置被保存在ans[1],ans[2],ans[3]...
        //要求每次插入后的lis,因为可以保证每次插入的数字比之前的大,所以只要插入的位置比之前数字的位置大就能保证lis,等价于求ans[i]的lis
        //求lis,每次找到第一个比ans[i]大的,将其替换成ans[i]
        memset(dp,0,sizeof dp);
        int len=0;
        for(int i=1;i<=n;i++){
            int k=lower_bound(dp+1,dp+1+len,ans[i])-dp;
            len=max(len,k);
            dp[k]=ans[i];
            printf("%d\n",len);
        }
        puts("");
    }
    return 0;
}

 

线段树单点更新解插空问题

标签:algorithm   int   等价   插入   string   pre   size   fine   sizeof   

原文地址:https://www.cnblogs.com/zsben991126/p/9898864.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!