• 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
    ",sum[1]);
    67     }
    68     return 0;
    69 }

      

    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    .net破解二(修改dll)
    CLR 的执行模型(2)
    理解数据库的几种键和几个范式
    事务隔离级别如何影响锁
    c#和java中封装字段的不同
    Linux安装AUTOCONF和AUTOMAKE产生的程序的一般步骤
    html锚点使用示例
    webbrowser控件使用时的注意事项
    C#实现单实例运行
    为Exchange 2007 SCC 启用 SCR 副本-供需要的人使用!
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/8313190.html
Copyright © 2020-2023  润新知