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
原文地址:https://www.cnblogs.com/little-w/p/3877313.html