刷漆升级线段树优化

题目描述

这次是机器人来刷漆啦。先在有n面排列在一起的墙,有一个机器人,每次会对一段墙进行刷漆,把这段墙随机的刷成黑色或者白色。请问机器人刷完之后,这n面墙呈现的颜色会有多少种不同的情况?

输入
第一行一个整数n。接下来n行,表示机器人依次要刷的地方。每行两整数LR,表示机器人要对 [L,R]这段墙进行刷漆。答案对1000000007取余。

输出

输出最后n面墙呈现的颜色会有多少种不同的情况?

样例输入

3

1 1

2 2

3 3

 

4

1 3

2 4

1 4

2 3

样例输出

8

4

提示


样例1,每个区间是相互独立的,每个区间都有两种颜色可选,答案2^3
对于30%的数据,n的范围[1,20];    
对于60%的数据,n的范围[1,200];
对于80%的数据,n的范围[1,2000];
对于100%的数据,n的范围[1,200000];

首先要明白这是按照顺序刷下来后来刷的会把前面刷的给覆盖掉,所以问题可以转化为请问到最后 1到n这段区间被划分为k个区间答案即为2^k

可以选择每一次刷漆都将这一段区间内的数字重新赋值

80分的数据可以暴力for+mark

然而100分就需要就高效的更新和查找很自然引入了线段树数据结构

如果一个区间[L,R]内有两个或以上不同的数字出现c为-1  查询时遇到-1的时候需要继续将区间劈开两半查询,如果不是-1就可以直接mark一下然后ans*=2

代码如下:

#include<stdio.h>

#include<string.h>

#include<iostream>

#include<algorithm>

#define M 200005

#define Mod 1000000007

using namespace std;

struct node{

   int L,R,c;

}tree[4*M];

int ans=1;

bool mark[M];

void Read(int &a){

   char ch;a=0;ch=getchar();

   while(!(ch>='0'&&ch<='9'))ch=getchar();

   while((ch>='0'&&ch<='9')){a=a*10+ch-'0';ch=getchar();}

}

void down(int p){

         if(tree[p].c==-1)return;

         tree[p*2].c=tree[p*2+1].c=tree[p].c;

}

void up(int p){

         if(tree[2*p].c==tree[2*p+1].c)tree[p].c=tree[2*p+1].c;

         elsetree[p].c=-1;

}

void build(int L,int R,int p){

   tree[p].L=L,tree[p].R=R,tree[p].c=0;

   if(L==R)return;

   int mid=(L+R)>>1;

   build(L,mid,p<<1);

   build(mid+1,R,p<<1|1);

}

void update(int L,int R,int p,int x){

         if(tree[p].L==L&&tree[p].R==R){

                   tree[p].c=x;

                   return;

    }

   int mid=(tree[p].L+tree[p].R)>>1;

         down(p);

         if(R<=mid)update(L,R,p<<1,x);

   else if(L>mid)update(L,R,p<<1|1,x);

   else{

       update(L,mid,p<<1,x);

       update(mid+1,R,p<<1|1,x);

    }

         up(p);

}

void query(int L,int R,int p){

         if(tree[p].L==L&&tree[p].R==R&&tree[p].c!=-1){

                   if(!mark[tree[p].c]){

                            mark[tree[p].c]=1;ans=ans*2%Mod;

                   }

                   return;

         }

         intmid=(tree[p].L+tree[p].R)>>1;

         down(p);

         if(R<=mid)query(L,R,p<<1);

   else if(L>mid)query(L,R,p<<1|1);

   else{

       query(L,mid,p<<1);

       query(mid+1,R,p<<1|1);

    }

}

int main(){

         intn,a,b;

         Read(n);

         build(1,n,1);

         mark[0]=1;//题目有点坑 一开始的墙是固定的 不能涂黑白颜色

         for(inti=1;i<=n;i++){

                   Read(a);Read(b);

                   update(a,b,1,i);

         }

         query(1,n,1);

//      for(inti=1;i<=7;i++)printf("%d %d %d\n",tree[i].L,tree[i].R,tree[i].c);

         printf("%d",ans);

         return0;

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值