CF915E Physical Education Lessons

题目链接:http://codeforces.com/contest/915/problem/E

题目大意:

  有 \(n\) 天(一开始都是工作日),之后会发布 \(q\) 个通知,通知的格式为:\(l\) \(r\) \(k\)。如果 \(k=1\),就说明从第 \(l\) 天到第 \(r\) 天都变成非工作日;如果 \(k=2\),就说明从第 \(l\) 天到第 \(r\) 天都变成工作日。问最后有多少个工作日。

知识点:  线段树、离散化

解题思路:

  将(区间左端点)与(区间右端点加一)进行离散化,如此线段树维护的叶子是相邻的两个离散点之间的左闭右开区间,在此基础上进行增删操作即可。线段树似乎不是这道题的最优解,时间卡的非常极限,需要加一点剪枝才能AC,可以参考一下注释。

AC代码:

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 #define lson l,m,rt<<1
 5 #define rson m+1,r,rt<<1|1
 6 const int maxn = 6e5+30;
 7 
 8 struct Input{
 9     int l,r,k;
10 }inp[maxn>>1];
11 int numbers[maxn],len[maxn];
12 map<int,int> index;
13 int sum[maxn<<2],lens[maxn<<2];//lens记录该区间的“总”长度,sum记录该区间的工作日数
14 int lazy[maxn<<2];  //lazy—— -1,void;1,增;0,删。
15 
16 void pushdown(int l,int r,int rt){
17     lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
18     int m=(l+r)>>1;
19     sum[rt<<1]=lens[rt<<1]*lazy[rt],sum[rt<<1|1]=lens[rt<<1|1]*lazy[rt];
20     lazy[rt]=-1;
21 }
22 void pushup(int rt){
23     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
24 }
25 void build(int l,int r,int rt){
26     lazy[rt]=-1;
27     if(l==r){
28         sum[rt]=lens[rt]=len[l];
29         return;
30     }
31     int m=(l+r)>>1;
32     build(lson);    build(rson);
33     sum[rt]=lens[rt]=lens[rt<<1]+lens[rt<<1|1];
34 } 
35 void update(int L,int R,int c,int l,int r,int rt){
36     if((sum[rt]==lens[rt]&&c)||(sum[rt]==0&&!c))    return; //在此处剪枝:如果这个区间已经满了(sum[rt]==lens[rt])此时再增加(c==1)就没有意义了,所以return;另一个同理。
37     if(L<=l&&r<=R){
38         sum[rt]=lens[rt]*c;
39         lazy[rt]=c;
40         return;
41     }
42     if(lazy[rt]!=-1&&l<r)   pushdown(l,r,rt);
43     int m=(l+r)>>1;
44     if(L<=m)    update(L,min(R,m),c,lson);
45     if(R>m)     update(max(L,m),R,c,rson);
46     pushup(rt);
47 }
48 int main(){
49     int n,q,t=0;
50     scanf("%d%d",&n,&q);
51     for(int i=0;i<q;i++){
52         scanf("%d%d%d",&inp[i].l,&inp[i].r,&inp[i].k);
53         inp[i].k--,inp[i].r++;  //区间右端点加一,k减一(如此0即为删,1即为增)
54         numbers[t++]=inp[i].l,numbers[t++]=inp[i].r;
55     }
56     numbers[t++]=1,numbers[t++]=n+1;
57     sort(numbers,numbers+t);
58     int m=unique(numbers,numbers+t)-numbers;
59     for(int i=0;i<m;i++){
60         index[numbers[i]]=i;
61         if(i<m-1)   len[i]=numbers[i+1]-numbers[i];
62     }
63     build(0,m-2,1);
64     for(int i=0;i<q;i++){
65         update(index[inp[i].l],index[inp[i].r]-1,inp[i].k,0,m-2,1); //这部分比较费解:我们离散化的是点,但是线段树维护的是区间。
66         printf("%d\n",sum[1]);
67     }
68     return 0;
69 }

 

  

posted @ 2018-01-18 21:44  Blogggggg  阅读(444)  评论(0编辑  收藏  举报