• 2014 summer 知识点总结1之线段树


    HDU 1166

    【题意】:

    n个阵营一字排开,每个初始有a[i]个人。现有两种操作:

    Q a b 查询[a,b]之间总人数并输出

    A/S a b 在a号位添加/删除b个人

    【分析】:最基本的单点更新和区间查询,维护节点信息sum[o]

    【代码】:

     1 #include <iostream>
     2 #include <string.h>
     3 #include <stdio.h>
     4 
     5 using namespace std;
     6 
     7 int numv[50005<<2];
     8 int A[50005];
     9 
    10 void builtTree(int o,int l,int r){
    11     if(l==r) {
    12         numv[o]=A[l];
    13         return ;
    14     }
    15     int m=l+(r-l)/2;
    16     builtTree(2*o,l,m);
    17     builtTree(2*o+1,m+1,r);
    18     numv[o]=numv[2*o]+numv[2*o+1];
    19     return ;
    20 }
    21 void Update(int o,int l,int r,int p,int x){
    22     if(l==r && l==p){
    23         A[l]=x;
    24         numv[o]=x;
    25         return ;
    26     }
    27     int m=l+(r-l)/2;
    28     if (p<=m) Update(2*o,l,m,p,x);
    29     if (p>=m+1)Update(2*o+1,m+1,r,p,x);
    30     numv[o]=numv[2*o]+numv[2*o+1];
    31 }
    32 int Query(int ql,int qr,int o,int l,int r){
    33     if (ql<=l && r<=qr) return numv[o];
    34     int m=l+(r-l)/2;
    35     int ans=0;
    36     if (ql<=m) ans+=Query(ql,qr,2*o,l,m);
    37     if (m+1<=qr) ans+=Query(ql,qr,2*o+1,m+1,r);
    38     return ans;
    39 }
    40 int t,n;
    41 int main(){
    42     scanf("%d",&t);
    43     for(int cas=1;cas<=t;cas++){
    44         scanf("%d",&n);
    45         printf("Case %d:
    ",cas);
    46         for(int i=1;i<=n;i++) scanf("%d",&A[i]);
    47         builtTree(1,1,n);
    48         char s[105];
    49         while(~scanf("%s",s)){
    50             if (s[0]=='E') {
    51                 break;
    52             }
    53             int a,b;
    54             scanf("%d%d",&a,&b);
    55             if (s[0]=='Q'){
    56                 int ans=Query(a,b,1,1,n);
    57                 printf("%d
    ",ans);
    58             }
    59             if (s[0]=='A'){
    60                 Update(1,1,n,a,A[a]+b);
    61             }
    62             if (s[0]=='S'){
    63                 Update(1,1,n,a,A[a]-b);
    64             }
    65         }
    66     }
    67     return 0;
    68 }
    View Code

    HDU 1754

    【题意】:给n个数字。m次操作,每次操作更新一个数字或者查询区间最大值。

    【分析】:基本单点更新区间查询,维护节点信息max[o]

    【代码】:

     1 #include <iostream>
     2 #include <string.h>
     3 #include <stdio.h>
     4 #define Mod 1000000007
     5 #define LL long long
     6 #define toL 2*o,l,m
     7 #define toR 2*o+1,m+1,r
     8 using namespace std;
     9 
    10 int maxv[200005<<2];
    11 int A[200005];
    12 
    13 void builtTree(int o,int l,int r){
    14     if (l==r){
    15         maxv[o]=A[l];
    16         return ;
    17     }
    18     int m=(l+r)/2;
    19     builtTree(toL);
    20     builtTree(toR);
    21     maxv[o]=max(maxv[2*o],maxv[2*o+1]);
    22     return ;
    23 }
    24 void Updata(int o,int l,int r,int p,int x){
    25     if (l==r && p==l){
    26         maxv[o]=x;
    27         return ;
    28     }else {
    29         int m=(r+l)/2;
    30         if (p<=m) Updata(toL,p,x);
    31         if (m+1<=p) Updata(toR,p,x);
    32         maxv[o]=max(maxv[2*o],maxv[2*o+1]);
    33         return ;
    34     }
    35 }
    36 int Query(int o,int l,int r,int ql,int qr){
    37     if (ql<=l && r<=qr) return maxv[o];
    38     int m=(r+l)/2;
    39     int ans=-1;
    40     if (ql<=m) ans=max(ans,Query(toL,ql,qr));
    41     if (m+1<=qr) ans=max(ans,Query(toR,ql,qr));
    42     return ans;
    43 }
    44 int n,q;
    45 
    46 int main(){
    47     while(~scanf("%d%d",&n,&q)){
    48         for(int i=1;i<=n;i++) scanf("%d",&A[i]);
    49         builtTree(1,1,n);
    50         for(int i=1;i<=q;i++){
    51             int a,b;
    52             char s[3];
    53             scanf("%s%d%d",s,&a,&b);
    54             if (s[0]=='Q'){
    55                 printf("%d
    ",Query(1,1,n,a,b));
    56             }
    57             if (s[0]=='U'){
    58                 Updata(1,1,n,a,b);
    59             }
    60         }
    61     }
    62     return 0;
    63 }
    View Code

    HDU 1394

    【题意】:就是给出一串数,当依次在将第一个数变为最后一个数的过程中,要你求它的最小逆序数。

    【分析】:每次维护sumv求区间内有多少个数字,处理出LOW[],UP[]后利用sum每次枚举

           for(int i=1;i<=n;i++){
                scanf("%d",&A[i]);
                A[i]++;
            //    cout<<"Q="<<Query(1,1,n,A[i]+1,n)<<endl;
                if (A[i]+1<=n) sum+=Query(1,1,n,A[i]+1,n);
                updata(1,1,n,A[i],1);//令A【i】的位置为1,那么sunv就相当于一个求和了
                A[i]--;//信息已经保存到树中,A[i]可还原
            }

    【代码】:

     1 /*HDU1394搜索写法*/
     2 #include <iostream>
     3 #include <string.h>
     4 #include <stdio.h>
     5 #define LL 2*o,l,m
     6 #define LR 2*o+1,m+1,r
     7 using namespace std;
     8 
     9 int A[50005];
    10 int Low[50005],Up[50005];
    11 int numv[50005<<2];//[1...50005]有多少个数
    12 
    13 int Query(int o,int l,int r,int ql,int qr){
    14     if (ql<=l && r<=qr) return numv[o];
    15     int m=(r+l)>>1;
    16     int ans=0;
    17     if (ql<=m) ans+=Query(LL,ql,qr);
    18     if (m+1<=qr) ans+=Query(LR,ql,qr);
    19     return ans;
    20 }
    21 void updata(int o,int l,int r,int p,int x){
    22    // cout<<"l="<<l<<","<<"r="<<r<<endl;
    23 
    24     if (l==r && p==l) {
    25         numv[o]=1;
    26         return ;
    27     }
    28     int m=(r+l)>>1;
    29     if (p<=m)updata(LL,p,x);
    30     if (m+1<=p)updata(LR,p,x);
    31     numv[o]=numv[2*o]+numv[2*o+1];
    32     return;
    33 }
    34 int main(){
    35     int n;
    36     while(~scanf("%d",&n)){
    37         memset(numv,0,sizeof(numv));
    38         int ans,sum=0;
    39         for(int i=1;i<=n;i++){
    40             scanf("%d",&A[i]);
    41             A[i]++;
    42         //    cout<<"Q="<<Query(1,1,n,A[i]+1,n)<<endl;
    43             if (A[i]+1<=n) sum+=Query(1,1,n,A[i]+1,n);
    44             updata(1,1,n,A[i],1);//令A【i】的位置为1,那么sunv就相当于一个求和了
    45             A[i]--;//信息已经保存到树中,A[i]可还原
    46         }
    47         ans=sum;
    48         for(int i=0;i<n;i++){
    49             Low[i]=i;
    50             Up[i]=n-i-1;
    51         }
    52         for(int i=1;i<=n-1;i++){
    53             sum=sum+(Up[A[i]]-Low[A[i]]);
    54             ans=min(sum,ans);
    55         }
    56         printf("%d
    ",ans);
    57     }
    58     return 0;
    59 }
    View Code

     HDU 2795

    【题意】:有一块长方形的广告板,往上面贴广告,然后给n个1*wi的广告,要求把广告贴上去,如果前面的行可以贴,就要贴前面的并且要靠左贴,前面的贴不下就贴在下面,广告的高度是wi,如果能贴在上面输出最小的高度,如果不能就输出-1。

    【分析】:以h为轴建立线段树,每次维护区间内剩余A[i]的最大值max[o],假设我们要新增的广告的长度为L

    那么,当max[o]<L的时候肯定已经不能放置,因为每次挨着左边的放,所以每次剩余的A[i]=A[i]-L即可

    【代码】:

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<string.h>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #define Lson l,m,2*o
     7 #define Rson m+1,r,2*o+1
     8 using namespace std;
     9 int maxv[200100<<2];
    10 void updata(int l,int r,int o,int p,int x){
    11     if (l==r){
    12         maxv[o]=x;
    13         return ;
    14     }else {
    15         int m=(l+r)>>1;
    16         if (p<=m)updata(Lson,p,x);
    17         else updata(Rson,p,x);
    18         maxv[o]=max(maxv[2*o],maxv[2*o+1]);
    19     }
    20     return ;
    21 }
    22 int h,w,n;
    23 void builtTree(int l,int r,int o){
    24     if (l==r) {
    25         maxv[o]=w;
    26         return ;
    27     }
    28     int m=(r+l)>>1;
    29     builtTree(Lson);
    30     builtTree(Rson);
    31     maxv[o]=max(maxv[2*o],maxv[2*o+1]);
    32     return ;
    33 }
    34 int Query(int l,int r,int o,int x){
    35     if (l==r){
    36         updata(1,h,1,l,maxv[o]-x);
    37         return l;
    38     }else {
    39         int m=(r+l)>>1;
    40         if (maxv[2*o]>=x) return Query(Lson,x);
    41         else return Query(Rson,x);
    42     }
    43 }
    44 int main(){
    45     while(~scanf("%d%d%d",&h,&w,&n)){
    46         if (h>n) h=n;
    47         builtTree(1,h,1);
    48         while(n--){
    49             int x;
    50             scanf("%d",&x);
    51             if (maxv[1]<x)//没有任何地方可以放
    52             {
    53                 puts("-1");
    54             }else {
    55                 printf("%d
    ",Query(1,h,1,x));
    56             }
    57         }
    58     }
    59     return 0;
    60 }
    View Code

    POJ 3468

    【题意】:给你N个数,Q个操作,操作有两种,‘Q a b ’是询问a~b这段数的和,‘C a b c’是把a~b这段数都加上c。

    【分析】:成段更新,每次给区间的每个元素加上C,那么当用到下层节点的时候,再把标记下传,更新区间即可,标记是这个区间的每个数要增加的C值,

    当一段被重复覆盖时,更新C即可,当标记下传后,这段区间的sum已经增加过了len*C,那么区间对应的标记减去C即可。区间标记的C为0时,表示更新完毕了。

    【代码】:

     1 /*poj3468
     2 */
     3 #include<iostream>
     4 #include<stdio.h>
     5 #include<string.h>
     6 #include<algorithm>
     7 #include<stdlib.h>
     8 #define Lson l,m,2*o
     9 #define Rson m+1,r,2*o+1
    10 #define LL long long
    11 using namespace std;
    12 
    13 LL sum[100010<<2];
    14 LL add[100010<<2];
    15 LL A[100010];
    16 void PushDown(int o,int len){
    17     if (add[o]){
    18         add[2*o]+=add[o];
    19         add[2*o+1]+=add[o];
    20         sum[2*o]+=add[o]*(len-(len>>1));
    21         sum[2*o+1]+=add[o]*(len>>1);
    22         add[o]=0;
    23     }
    24     return ;
    25 }
    26 void PushUp(int o){
    27     sum[o]=sum[2*o]+sum[2*o+1];
    28 }
    29 void builtTree(int l,int r,int o){
    30     add[o]=0;
    31     if (l==r){
    32         sum[o]=A[l];
    33     }else {
    34         int m=(l+r)>>1;
    35         builtTree(Lson);
    36         builtTree(Rson);
    37         PushUp(o);
    38     }
    39     return ;
    40 }
    41 LL Query(int l,int r,int o,int L,int R){
    42     if (L<=l && r<=R){
    43         return sum[o];
    44     }
    45     PushDown(o,r-l+1);
    46     int m=(l+r)>>1;
    47     LL ans=0;
    48     if (L<=m) ans+=Query(Lson,L,R);
    49     if (m+1<=R) ans+=Query(Rson,L,R);
    50     return ans;
    51 }
    52 void Updata(int l,int r,int o,int L,int R,int x){
    53     if (L<=l && r<=R){
    54         sum[o]+=(LL)(r-l+1)*(LL)x;
    55         add[o]+=x;
    56         return ;
    57     }
    58     PushDown(o,r-l+1);
    59     int m=(r+l)>>1;
    60     if (L<=m) Updata(Lson,L,R,x);
    61     if (m+1<=R) Updata(Rson,L,R,x);
    62     PushUp(o);
    63     return ;
    64 }
    65 int N,Q;
    66 int main(){
    67 ////    freopen("out.txt","w",stdout);
    68     while(~scanf("%d%d",&N,&Q)){
    69         for(int i=1;i<=N;i++) scanf("%lld",&A[i]);
    70         builtTree(1,N,1);
    71         char s[10];
    72         while(Q--){
    73             scanf("%s",s);
    74             int l,r,x;
    75             if (s[0]=='Q'){
    76                 scanf("%d%d",&l,&r);
    77                 printf("%lld
    ",Query(1,N,1,l,r));
    78             }
    79             if (s[0]=='C'){
    80                 scanf("%d%d%d",&l,&r,&x);
    81                 Updata(1,N,1,l,r,x);
    82             }
    83         }
    84     }
    85     return 0;
    86 }
    View Code

    POJ 2528

    【题意】:那个城市里要竞选市长,然后在一块墙上可以贴海报为自己拉票,每个人可以贴连续的一块区域,后来帖的可以覆盖前面的,问到最后一共可以看到多少张海报。1 <= n <= 10000 ,1 <= i <= n, 1 <= li <= ri <= 10000000 .

    【分析】:首先看这个N的范围,基本上是和区间有关的操作。

    如果把新增一张海报 I 当做把一个区间的数字都变成 I+1,我们想要的是一段区间里不同的数字的个数num[o]。

    显然,我们不可能把一个区间的数字都更新完了再花O(R-L)的时间更新这个值num[o]。

    那么怎么办呢?我们向区间的合并上考虑。

    【代码】:具体的分析看代码注释:

    /*解题的重点:
    1、区间更新成一个数,用lazy标记
    2、左边的范围很大,用离散化
    3、离散化处理,二分查找出x的对应序号
    4、查询,对于col[o]>0的区间说明,这个区间都是col[o],直接ans+1返回即可
    但是因为计算的是露出的海报的总的种数,所以查找过的点不需要再计算。
    也能保证单点的col[o]大于0,因为col标记不需要下传
    5、但是题目略有歧义,这个更新的(l,r)是不是坐标轴上的点呢?
    是的话,要处理成(l,r-1)。
    */

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<string.h>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<map>
     7 #define Lson l,m,2*o
     8 #define Rson m+1,r,2*o+1
     9 #define LL long long
    10 using namespace std;
    11 
    12 int lx[41111];
    13 int rx[41111];
    14 int px[41111<<1];
    15 int col[41111<<3];
    16 bool vis[41111<<1];
    17 
    18 /*解题的重点:
    19 1、区间更新成一个数,用lazy标记
    20 2、左边的范围很大,用离散化
    21 3、离散化处理,二分查找出x的对应序号
    22 4、查询,对于col[o]>0的区间说明,这个区间都是col[o],直接ans+1返回即可
    23 但是因为计算的是露出的海报的总的种数,所以查找过的点不需要再计算。
    24 也能保证单点的col[o]大于0,因为col标记不需要下传
    25 5、但是题目略有歧义,这个更新的(l,r)是不是坐标轴上的点呢?
    26 是的话,要处理成(l,r-1)。
    27 */
    28 int T,N,cnt,ans;
    29 int binary(int n,int x){//px[0]--px[n-1]中找到x
    30     int ans;
    31     ans=lower_bound(px,px+n,x)-px;
    32     return ans+1;
    33 }
    34 void PushDown(int o){
    35     if (col[o]){
    36         col[2*o]=col[o];
    37         col[2*o+1]=col[o];
    38         col[o]=0;
    39     }
    40     return;
    41 }
    42 
    43 void Query(int l,int r,int o){//
    44     if (col[o]){//以区间代替点
    45         if (!vis[col[o]]){//不必查找到每一个点,区间代替下面的每个单点即可
    46             ans++;
    47             vis[col[o]]=true;
    48         }
    49         return ;
    50     }
    51     if (l==r) return ;//单点保证在上面处理过了
    52     int m=(l+r)>>1;
    53     Query(Lson);
    54     Query(Rson);
    55 }
    56 void Updata(int l,int r,int o,int L,int R,int x){
    57     if (L<=l&&r<=R){//给找到的区间加懒惰标记
    58         col[o]=x;
    59         return ;
    60     }
    61     PushDown(o);//若是要向下层更新,那么懒惰标记要下传
    62     int m=(l+r)>>1;
    63     if (L<=m) Updata(Lson,L,R,x); //继续向下搜索更新
    64     if (m+1<=R) Updata(Rson,L,R,x);
    65     return ;
    66 }
    67 int main(){
    68     scanf("%d",&T);
    69     while(T--){
    70         scanf("%d",&N);
    71         cnt=0;
    72         for(int i=0;i<N;i++){//离散化
    73             scanf("%d",&lx[i]);
    74             scanf("%d",&rx[i]);
    75             px[cnt++]=lx[i];
    76             px[cnt++]=rx[i];
    77         }
    78         sort(px,px+cnt);
    79         int cnt2=0;
    80         px[cnt]=-1;
    81         for(int i=0;i<cnt;i++){
    82             if (px[i]!=px[i+1]) px[cnt2++]=px[i];//去重并且按顺序统计离散的点
    83         }
    84         ans=0;
    85         memset(vis,0,sizeof(vis));
    86         memset(col,0,sizeof(col));
    87         for(int i=0;i<N;i++){
    88             int k1=binary(cnt2,lx[i]),k2=binary(cnt2,rx[i]);//二分查找到标号
    89             Updata(1,cnt2,1,k1,k2,i+1);
    90         }
    91         Query(1,cnt2,1);
    92         printf("%d
    ",ans);
    93 
    94     }
    95     return 0;
    96 }
    View Code

    POJ 3667 (重难点)

    【题意】:

    有N个房间,M次操作。1 a表示找到连续的长度为a的空房间,如果有多解,优先左边的,即表示入住,输出入住的人的最左边的房间号。2 b len把起点为b长度的len的房间清空,即退房。

    【分析】:

    假设:如果房间没人,标记为1,否则标记为0

    首先,我们肯定是想快速查找出一段区间内是否有满足的连续长度的0的存在,但是线段树的区间已经固定好了。

    但是有可能存在两个区间合起来中间有长度为L的连续空房间。

    那么我们就要维护:

    Lsum[o]:区间左边连续的0的个数

    Rsum[o]:区间右边连续的0的个数

    Msum[o]: 区间中最大的连续的0的个数

    那么当我们查找区间o(保证Msum[o]>=Num)时,因为要尽量的向左分配,所以若Msum[2*o]当然向左分配,若Rsum[2*o]+Lsum[2*o+1]>=Num,则直接可以计算出入住的位置p= m-Rsum[2*o]+1;

    int Query(int l,int r,int o,int D){//向左搜索
        int m=(r+l)>>1;
        if (l==r){//当且D==1时才会有这个出口
            return l;
        }
        PushDown(o,r-l+1);
        if (max_sub[2*o]>=D){
            return Query(Lson,D);
        }else {
            if (max_suffix[2*o]+max_prefix[2*o+1]>=D){
                return m-max_suffix[2*o]+1;
            }
        }
        return Query(Rson,D);
    }
    区间更新:
    1、有两种:分别是一段区间更新为1,或 0
    2、Pushdown标记PushUp标记
    3、关键是同时维护:sum[o]
        if (L<=l && r<=R){
            col[o]=x;
            max_sub[o]=max_suffix[o]=max_prefix[o]=(r-l+1)*x;
            return;
        }
    4、区间合并,维护信息
    void PushUp(int l,int r,int o){
        int m=(r+l)>>1;
        int l1=m-l+1,l2=r-(m+1)+1;
        max_sub[o]=max(max_sub[2*o],max_sub[2*o+1]);
        max_sub[o]=max(max_sub[o],max_suffix[2*o]+max_prefix[2*o+1]);
        if (max_prefix[2*o]==l1){
            max_prefix[o]=l1+max_prefix[2*o+1];//整个区间可以合并
        }else max_prefix[o]=max_prefix[2*o];
        if (max_suffix[2*o+1]==l2){
            max_suffix[o]=l2+max_suffix[2*o];
        }else max_suffix[o]=max_suffix[2*o+1];
        return ;
    }

    【代码】:

      1 #include <iostream>
      2 #include <string.h>
      3 #include <stdio.h>
      4 #define maxn 51000
      5 #define Lson l,m,2*o
      6 #define Rson m+1,r,2*o+1
      7 using namespace std;
      8 int col[maxn<<2];
      9 int max_sub[maxn<<2];//连续的1的个数
     10 int max_prefix[maxn<<2];//靠左的连续的1的个数
     11 int max_suffix[maxn<<2];//靠右的连续的1的个数
     12 int N,M;
     13 void PushUp(int l,int r,int o){
     14     int m=(r+l)>>1;
     15     int l1=m-l+1,l2=r-(m+1)+1;
     16     max_sub[o]=max(max_sub[2*o],max_sub[2*o+1]);
     17     max_sub[o]=max(max_sub[o],max_suffix[2*o]+max_prefix[2*o+1]);
     18     if (max_prefix[2*o]==l1){
     19         max_prefix[o]=l1+max_prefix[2*o+1];//整个区间可以合并
     20     }else max_prefix[o]=max_prefix[2*o];
     21     if (max_suffix[2*o+1]==l2){
     22         max_suffix[o]=l2+max_suffix[2*o];
     23     }else max_suffix[o]=max_suffix[2*o+1];
     24     return ;
     25 }
     26 //1表示房间空,0表示不可用
     27 void PushDown(int o,int len)//因为有区间上的清零,所以要PushDown
     28 {
     29     if (col[o]==-1) return;
     30     col[2*o]=col[o];
     31     col[2*o+1]=col[o];
     32     if (col[o]==1){
     33         max_sub[2*o]=max_suffix[2*o]=max_prefix[2*o]=(len-(len>>1));
     34         max_sub[2*o+1]=max_suffix[2*o+1]=max_prefix[2*o+1]=len>>1;
     35     }
     36     if (col[o]==0){
     37         max_sub[2*o]=max_suffix[2*o]=max_prefix[2*o]=0;
     38         max_sub[2*o+1]=max_suffix[2*o+1]=max_prefix[2*o+1]=0;
     39     }
     40     col[o]=-1;
     41 }
     42 void Updata(int l,int r,int o,int L,int R,int x){
     43     if (L<=l && r<=R){
     44         col[o]=x;
     45         max_sub[o]=max_suffix[o]=max_prefix[o]=(r-l+1)*x;
     46         return;
     47     }
     48     PushDown(o,r-l+1);
     49     int m=(l+r)>>1;
     50     if (L<=m) Updata(Lson,L,R,x);
     51     if (m+1<=R) Updata(Rson,L,R,x);
     52     PushUp(l,r,o);
     53     return;
     54 }
     55 int Query(int l,int r,int o,int D){//向左搜索
     56     int m=(r+l)>>1;
     57     if (l==r){//当且D==1时才会有这个出口
     58         return l;
     59     }
     60     PushDown(o,r-l+1);
     61     if (max_sub[2*o]>=D){
     62         return Query(Lson,D);
     63     }else {
     64         if (max_suffix[2*o]+max_prefix[2*o+1]>=D){
     65             return m-max_suffix[2*o]+1;
     66         }
     67     }
     68     return Query(Rson,D);
     69 }
     70 
     71 void BuiltTree(int l,int r,int o){
     72     col[o]=-1;
     73     if (l==r){
     74         max_sub[o]=1;
     75         max_suffix[o]=1;
     76         max_prefix[o]=1;
     77         return ;
     78     }
     79     int m=(l+r)>>1;
     80     BuiltTree(Lson);
     81     BuiltTree(Rson);
     82     PushUp(l,r,o);
     83     return ;
     84 }
     85 int main(){
     86     while(~scanf("%d%d",&N,&M)){
     87         BuiltTree(1,N,1);
     88         int q,a,b;
     89         while(M--){
     90             scanf("%d",&q);
     91             if (q==1){
     92                 scanf("%d",&a);
     93                 if (max_sub[1]<a){
     94                     puts("0");
     95                 }else {
     96                     int k=Query(1,N,1,a);
     97                     printf("%d
    ",k);
     98                     Updata(1,N,1,k,k+a-1,0);
     99                 }
    100             }
    101             if (q==2){
    102                 scanf("%d%d",&a,&b);
    103                 Updata(1,N,1,a,a+b-1,1);
    104             }
    105         }
    106     }
    107     return 0;
    108 }
    View Code

    CodeForces 46D

    题意】:

    在长为L的(点0~点L)的线段上停车开车操作;

    停车 1 x:车长x,需要b+x+f的空余才能使车停进去,多个区域,选择最左边

    开车 2 x:第x次操作,停进的车,开出去

    分析】:

    和poj3667很相似,但是处理首位时要特判,同时记录下来第x次操作的车的长度和插入的位置,做插入或更新即可

    代码】:

      1 #include <iostream>
      2 #include <string.h>
      3 #include <stdio.h>
      4 #define maxn 110000
      5 #define Lson l,m,2*o
      6 #define Rson m+1,r,2*o+1
      7 #define LL long long
      8 using namespace std;
      9 int sum[maxn<<2];
     10 int lsum[maxn<<2];
     11 int rsum[maxn<<2];
     12 int col[maxn<<2];
     13 void PushUp(int o,int len){
     14     sum[o]=max(sum[2*o],sum[2*o+1]);
     15     sum[o]=max(sum[o],rsum[2*o]+lsum[2*o+1]);
     16     lsum[o]=lsum[2*o];
     17     if (lsum[2*o]==len-(len>>1)) lsum[o]+=lsum[2*o+1];
     18     rsum[o]=rsum[2*o+1];
     19     if (rsum[2*o+1]==len>>1) rsum[o]+=rsum[2*o];
     20     return;
     21 }
     22 void PushDown(int o,int len){
     23     if (col[o]==-1) return;//col==1,表示可以使用
     24     col[2*o]=col[2*o+1]=col[o];
     25     sum[2*o]=lsum[2*o]=rsum[2*o]=(len-(len>>1))*col[o];
     26     sum[2*o+1]=rsum[2*o+1]=lsum[2*o+1]= (len>>1)*col[o];
     27     col[o]=-1;
     28     return;
     29 }
     30 void Updata(int l,int r,int o,int L,int R,int x){
     31     if (L<=l && r<=R){
     32         col[o]=x;
     33         sum[o]=lsum[o]=rsum[o]=(r-l+1)*x;
     34         return ;
     35     }
     36     PushDown(o,r-l+1);
     37     int m=(r+l)>>1;
     38     if (L<=m) Updata(Lson,L,R,x);
     39     if (m+1<=R) Updata(Rson,L,R,x);
     40     PushUp(o,r-l+1);
     41     return ;
     42 }
     43 int Query(int l,int r,int o,int D){
     44 //    cout<<"l="<<l<<","<<"r="<<r<<endl;
     45 //    cout<<"sum="<<sum[o]<<endl;
     46     if (l==r) return l;
     47     PushDown(o,r-l+1);
     48     int m=(l+r)>>1;
     49     if (sum[2*o]>=D) return Query(Lson,D);
     50     else {
     51         if (rsum[2*o]+lsum[2*o+1]>=D){
     52             return m-rsum[2*o]+1;
     53         }
     54         return Query(Rson,D);
     55     }
     56 }
     57 void BuiltTree(int l,int r,int o){
     58     col[o]=-1;
     59     if (l==r){
     60         sum[o]=lsum[o]=rsum[o]=1;
     61         return ;
     62     }
     63     int m=(l+r)>>1;
     64     BuiltTree(Lson);
     65     BuiltTree(Rson);
     66     PushUp(o,r-l+1);
     67     return ;
     68 }
     69 int L,b,f;
     70 int px[110];
     71 int py[110];
     72 int main(){
     73 //    freopen("out.txt","w",stdout);
     74     while(~scanf("%d%d%d",&L,&b,&f)){
     75         int n;
     76         scanf("%d",&n);
     77         BuiltTree(1,L+b+f,1);
     78         for(int i=0;i<n;i++){
     79             int q,a;
     80             scanf("%d%d",&q,&a);
     81             if (q==1){
     82 //                cout<<"sum[1]:"<<sum[1]<<endl;
     83                 if (sum[1]<a+b+f){
     84                     puts("-1");
     85                     continue;
     86                 }
     87                 int p=Query(1,L+b+f,1,a+b+f);
     88 
     89                 p=p+b;
     90                 printf("%d
    ",p-b-1);
     91 
     92 //            cout<<"p="<<p<<endl;
     93                 px[i]=p;py[i]=p+a-1;
     94 //                cout<<"px="<<px[i]<<","<<"py="<<py[i]<<endl;
     95                 Updata(1,L+b+f,1,px[i],py[i],0);
     96             }
     97             if (q==2){
     98                 Updata(1,L+b+f,1,px[a-1],py[a-1],1);
     99             }
    100         }
    101     }
    102     return 0;
    103 }
    View Code

    HDU 2795

    题意】:算多个矩形的周长并

    分析】:《》

    代码】:

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<string.h>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #define Lson l,m,2*o
     7 #define Rson m+1,r,2*o+1
     8 using namespace std;
     9 int maxv[200100<<2];
    10 void updata(int l,int r,int o,int p,int x){
    11     if (l==r){
    12         maxv[o]=x;
    13         return ;
    14     }else {
    15         int m=(l+r)>>1;
    16         if (p<=m)updata(Lson,p,x);
    17         else updata(Rson,p,x);
    18         maxv[o]=max(maxv[2*o],maxv[2*o+1]);
    19     }
    20     return ;
    21 }
    22 int h,w,n;
    23 void builtTree(int l,int r,int o){
    24     if (l==r) {
    25         maxv[o]=w;
    26         return ;
    27     }
    28     int m=(r+l)>>1;
    29     builtTree(Lson);
    30     builtTree(Rson);
    31     maxv[o]=max(maxv[2*o],maxv[2*o+1]);
    32     return ;
    33 }
    34 int Query(int l,int r,int o,int x){
    35     if (l==r){
    36         updata(1,h,1,l,maxv[o]-x);
    37         return l;
    38     }else {
    39         int m=(r+l)>>1;
    40         if (maxv[2*o]>=x) return Query(Lson,x);
    41         else return Query(Rson,x);
    42     }
    43 }
    44 int main(){
    45     while(~scanf("%d%d%d",&h,&w,&n)){
    46         if (h>n) h=n;
    47         builtTree(1,h,1);
    48         while(n--){
    49             int x;
    50             scanf("%d",&x);
    51             if (maxv[1]<x)//没有任何地方可以放
    52             {
    53                 puts("-1");
    54             }else {
    55                 printf("%d
    ",Query(1,h,1,x));
    56             }
    57         }
    58     }
    59     return 0;
    60 }
    View Code

    HDU 1542

    题意】:算多个矩形的面积并

    分析】:《》

    代码】:

     1 #include <iostream>
     2 #include <string.h>
     3 #include <stdio.h>
     4 #include <algorithm>
     5 #define Lson l,m,2*o
     6 #define Rson m+1,r,2*o+1
     7 
     8 using namespace std;
     9 double Y[255];//hash映射
    10 double len[255<<2];
    11 int add[255<<2];
    12 int n,cas=0,cnt1,cnt2;
    13 int binary(double key){
    14     int l=0,r=cnt1-1;
    15     while(l<r){
    16         int m=(l+r)>>1;
    17         if (Y[m]==key) return m;
    18         if (Y[m]<key) l=m+1;
    19         if (Y[m]>key) r=m;
    20     }
    21     return l;
    22 }
    23 void PushUp(int o,int l,int r){
    24     if (add[o]>0){
    25         len[o]=Y[r+1]-Y[l];
    26     }else {
    27         if (l==r) len[o]=0;
    28         else {
    29             len[o]=len[o*2]+len[2*o+1];
    30         }
    31     }
    32     return ;
    33 }
    34 void Updata(int l,int r,int o,int L,int R,int c){
    35     if (L<=l && r<=R){
    36         add[o]+=c;
    37         PushUp(o,l,r);
    38         return ;
    39     }
    40     int m=(r+l)>>1;
    41     if (L<=m) Updata(Lson,L,R,c);
    42     if (m+1<=R) Updata(Rson,L,R,c);
    43     PushUp(o,l,r);
    44     return ;
    45 }
    46 struct Line {
    47     double p;
    48     double _d,_u;
    49     int c;
    50     bool operator<(const Line&X)const{
    51         if (p==X.p) return c>X.c;
    52         else return p<X.p;
    53     }
    54 }Lines[255];
    55 int main(){
    56     while(~scanf("%d",&n)&&n){
    57         cas++;
    58         cnt1=cnt2=0;
    59         for(int i=0;i<n;i++){
    60             double x1,y1,x2,y2;
    61             scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
    62             Y[cnt1++]=y1;Y[cnt1++]=y2;
    63             Lines[cnt2++]=(Line){x1,y1,y2,1};
    64             Lines[cnt2++]=(Line){x2,y1,y2,-1};
    65         }
    66         sort(Y,Y+cnt1);//建立i到Y的映射
    67         sort(Lines,Lines+cnt2);
    68 
    69         double ans=0;
    70         for(int i=0;i<cnt2;i++){
    71             int k1=binary(Lines[i]._d),k2=binary(Lines[i]._u);
    72             Updata(0,cnt1,1,k1,k2-1,Lines[i].c);
    73             ans+=len[1]*(Lines[i+1].p-Lines[i].p);
    74         }
    75         printf("Test case #%d
    ",cas);
    76         printf("Total explored area: %.2lf
    
    ",ans);
    77     }
    78     return 0;
    79 }
    View Code
  • 相关阅读:
    Try .NET & Github Gist
    vue & font-awesome
    JSP基础与提高(一).md
    chm转换为html文件
    markdownpad生成目录
    MarkdownPad2的密钥
    删除多余的win10软件
    计算机组成原理与机构期末复习的概念
    sublime text 的小细节设置,让你的代码更优美
    NetBeans主题配色方案加设置.md
  • 原文地址:https://www.cnblogs.com/little-w/p/3877313.html
Copyright © 2020-2023  润新知