新年彩灯Ⅰ

Description

新年将至,YY准备挂一排彩灯,已知彩灯刚挂完的彩灯共有N盏(编号为1,2,3,……),并且都是灭的。彩灯的闪烁由一段程序控制。

每一秒钟程序会生成两个正整数a和b(1<=a,b<=N),然后将编号为a和b之间的所有灯的状态改变一次,即如果灯i是灭的,那么经过一次改变,灯i会亮,如果灯i是亮的,经过一次改变,灯i会灭。

 

当YY看着自己挂的彩灯不断闪烁的时候,问题来了,YY想知道任意时刻某一区间灯的状态。

 

Input

多组测试数据,每一组第一行是一个整数N(1<=N<=1000000)和一个整数M(1<=M<=3000)。

 

然后是M行数据,包括以下两种形式:

         1 a b 表示灯a和灯b之间的灯(含灯a和灯b)变换一次状态。

         0 x y 表示YY想知道此刻灯x到灯y(包含灯x和灯y)的状态.

 

Output

对于每次YY想知道结果的时候,输出一行灯的状态(编号小的灯优先),如果是亮的输出”1”,否则输出”0”;

 

Sample Input

3 3 1 1 2 1 2 3 0 1 3

Sample Output

101

分析

给你一串灯泡,然后有m次操作,

要么是对一片区域里的灯泡状态进行一次修改,

要么是输出一个区域里的所有灯泡的状态。

如果是仅仅实现这个功能其实并不复杂

代码如下

#include <bits/stdc++.h>
#define maxn 1000005
using namespace std;
 int a[maxn],b[maxn],c[maxn];
 int n,m;
int main()
{
   while(cin>>n>>m)
   {
    int x,y,z;
    memset(a,0,sizeof(a));
    首先将所有灯泡都关上
    for(int i=0;i<m;i++)
    {
        cin>>x>>y>>z;
        if(y>z)
        swap(y,z);
        if(x==1)
        {
            for(int i=y;i<=z;i++)
            {
                if(a[i]==0)
                a[i]=1;
                else
                a[i]=0;
               改变所有目标区域的灯泡的状态
               }
                
           }
           else
           for(int i=y;i<=z;i++)
            cout<<a[i];
            输出目标区域的灯泡的状态
            cout<<endl;
       }
     
     
   }
    return 0;
}

是不是很简单,

然后我成功超时了

为什么呐

因为不论是修改操作还是输出操作时间复杂度都是O(n),总的时间复杂度就是O(m*n);

所以这个代码理所当然的超时了。

然后有什么办法呐,

当然就是用树状数组

树状数组干同样的事复杂度却是O(M*lgN),

别小看这个lg,很大的数一lg就很小了,

这个学过数学的都知道吧,不需要我说了。

#include <bits/stdc++.h>
#define maxn 1000005
using namespace std;
 int a[maxn];
 int n,m;
  void update(int p,int x)
 {
    while(p<=maxn)
    {
        a[p]+=x;
        p+=p&-p;
     }
}
void range_update(int l, int r,int x) 
{
    update(l,x);
    update(r + 1,-x);
}
 
     
 
 int query(int p) 
{
    int res = 0;
    while (p) res += a[p], p -= p & -p;
    return res;
}
 
  
  
int main()
{
   while(cin>>n>>m)
   {
    int x,y,z;
    memset(a,0,sizeof(a));
    for(int i=0;i<m;i++)
    {
        cin>>x>>y>>z;
        if(y>z)
        swap(y,z);
        if(x==1)
            range_update(y,z,1);
        else
        {
            for(int j=y;j<=z;j++)
            {
                int t=query(j);
                if(t%2)
                printf("1");
                else
                printf("0");
                 
            }
            printf("\n");
               }       
           }
          
       }
     
     
    
    return 0;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值