zoukankan      html  css  js  c++  java
  • Vijos1448题解---线段树+括号法

    描述

    校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……
    如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:
    K=1,K=1,读入l、r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同
    K=2,读入l,r表示询问l~r之间能见到多少种树(l,r>0)

    输入格式

    第一行n,m表示道路总长为n,共有m个操作
    接下来m行为m个操作

    输出格式

    对于每个k=2输出一个答案

     样例输入

    5 4

    1 1 3

    2 2 5

    1 2 4

    2 3 5

    样例输出

    1
    2
     
    普通的暴力算法,植树的时间为O(n),查询的时间也为O(n),所以总体的时间复杂度为O(nm)。
    这里介绍一种独特的想法---括号法。
    在植树区间的左端点放一个左括号“(”,右端点放一个右括号“)”,使得植树时间为O(1)。
    显而易见,查询的结果为右端点左边“(”的个数减去左端点左边“)”的个数,时间为O(n)。
    2至5之间有2-1=1种树。
    3至5之间有2-0=2种树。
    为了进一步优化时间复杂度,我们使用线段树维护左右括号的数量,使时间降到log级。
    献上代码:
     1 #include <cstdio>
     2 int n,m;
     3 struct node
     4 {
     5     int x,y;
     6     int a[3];//a[1]表示左括号的数量,a[2]表示右括号的数量。
     7 }t[300002];
     8 void init(int k,int l,int r)//初始化。
     9 {
    10     t[k].x=l;
    11     t[k].y=r;
    12     if(l==r)return;
    13     int mid=(l+r)/2;
    14     init(2*k,l,mid);
    15     init(2*k+1,mid+1,r);
    16 }
    17 void build(int k,int l,int op)
    18 {
    19     if(t[k].x<=l&&l<=t[k].y)//若在当前节点的范围内,括号数量加1。
    20         t[k].a[op]++;
    21     if(t[k].x==t[k].y)return;
    22     int mid=(t[k].x+t[k].y)/2;
    23     if(l<=mid)build(2*k,l,op);//查询左儿子。
    24     if(l>=mid+1)build(2*k+1,l,op);//查询右儿子。
    25 }
    26 int find(int k,int l,int r,int op)//查找l到r内括号的个数。
    27 {
    28     int ans=0;
    29     if(l<=t[k].x&&t[k].y<=r)return t[k].a[op];
    30     int mid=(t[k].x+t[k].y)/2;
    31     if(l<=mid)ans+=find(2*k,l,r,op);
    32     if(r>=mid+1)ans+=find(2*k+1,l,r,op);
    33     return ans;
    34 }
    35 int main()
    36 {
    37     int k,l,r,ans1,ans2;
    38     scanf("%d%d",&n,&m);
    39     init(1,1,n);
    40     for(int i=1;i<=m;i++)
    41     {
    42         scanf("%d%d%d",&k,&l,&r);
    43         if(k==1)
    44         {
    45             build(1,l,1);
    46             build(1,r,2);
    47         }
    48         if(k==2)
    49         {
    50             ans1=ans2=0;
    51             ans1=find(1,1,r,1);
    52             if(l-1>=1)ans2=find(1,1,l-1,2);
    53             printf("%d
    ",ans1-ans2);
    54         }
    55     }
    56     return 0;
    57 }
  • 相关阅读:
    IE和FF下面的css半透明效果
    javascript 文字滚动
    利用URLRewriter重写url
    “/”应用程序中的服务器错误。
    Iframe 参数列表
    【转】CSS的一些技巧
    ASP.NET 如何动态修改 title Meta link标签
    Test2.数据库批处理添加练习(mysql_java)
    html5(test1.提交表单)
    smartupload图片上传
  • 原文地址:https://www.cnblogs.com/c0per/p/5775043.html
Copyright © 2011-2022 走看看