【JZOJ 4603】颜料大乱斗

Description

画师傅又要开始画画了,这次他花了三天三夜将一堵墙涂成了白色。
但是画师傅有个顽劣的弟子小花,小花讨厌画师傅对Ta始乱终弃,所以趁 画师傅不在用不同的颜料将墙涂来涂去。
然而画师傅为了保护他的大作,设置了一个监控机制A。A每隔一段时间会 查珣某一段墙上的颜料的种类数,并将其记录下来。
现在画师傅回来了,看到五颜六色色彩斑斓灯火阑珊金碧辉煌的【哗】墙, 一口气没换上来,卒。
作为画师傅的好友杀小姐的你,为了追查画师傅的死因,于是调用了墙的监 控机制A的记录。于是,你看到了怎样的记录呢?

Solution

很显然,开30棵线段树即可,
但是:
有可能l>r啊!!!
白色是1啊!!!
复杂度:O(n30log(n))
要优化常数。

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++) 
using namespace std;
const int N=100500;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int n,m,ans;
int b[N*3][32],la[N*3];
int s[32];
void doit(int l,int r,int e)
{
    if(!la[e])return;
    fo(i,0,m)b[e][i]=0;
    b[e][la[e]]=r-l+1;
    if(l!=r)la[e*2]=la[e],la[e*2+1]=la[e];
    la[e]=0;
}
void build(int l,int r,int e)
{
    if(l==r)
    {
        b[e][1]=1;
        return;
    }
    int t=(l+r)/2;
    build(l,t,e*2);
    build(t+1,r,e*2+1);
    b[e][1]=r-l+1;
}
void change(int l,int r,int e,int l1,int r1,int l2)
{
    if(l==l1&&r==r1)
    {
        la[e]=l2;
        doit(l,r,e);
        return;
    }
    int t=(l+r)/2;
    doit(l,t,e*2),doit(t+1,r,e*2+1);
    if(r1<=t)change(l,t,e*2,l1,r1,l2);
        else if(t<l1)change(t+1,r,e*2+1,l1,r1,l2);
            else change(l,t,e*2,l1,t,l2),change(t+1,r,e*2+1,t+1,r1,l2);
    fo(i,0,m)b[e][i]=b[e*2][i]+b[e*2+1][i];
}
void find(int l,int r,int e,int l1,int r1)
{
    doit(l,r,e);
    if(l==l1&&r==r1)
    {
        fo(i,0,m)s[i]+=b[e][i];
        return;
    }
    int t=(l+r)/2;
    if(r1<=t)find(l,t,e*2,l1,r1);
        else if(t<l1)find(t+1,r,e*2+1,l1,r1);
            else find(l,t,e*2,l1,t),find(t+1,r,e*2+1,t+1,r1);
}
int main()
{
    int q,l,r,m_;
    read(n),read(m),read(m_);
    build(1,n,1);
    while(m_--)
    {
        char ch=' ';
        while(ch!='P'&&ch!='C')ch=getchar();
        read(l),read(r);
        if(r<l)swap(l,r);
        if(ch=='C')
        {
            read(q);
            change(1,n,1,l,r,q);
        }
        else 
        {
            ans=q=0;
            fo(i,0,m)s[i]=0;
            find(1,n,1,l,r);
            fo(i,1,m)if(s[i])ans++,q+=s[i];
            printf("%d\n",ans+(q<r-l+1));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值