[caioj]1100: [視訊]線段樹2(統計不同顏色)
阿新 • • 發佈:2019-02-08
1100: [視訊]線段樹2(統計不同顏色)
題目描述
【題目描述】有L段線段(編號為1~L, (1 <= L <= 1000000)),一開始全部線段是顏色1。
有兩種操作:
1、C A B tt :把第A至第B個線段染成第tt種顏色
2、P A B :詢問第A至第B個線段有多少種不一樣的顏色。
注意:
1、A有可能比B大。
2、顏色的編號<=50;
【輸入格式】
第一行含有三個整數 L and M (1 <= M <= 100000). M代表操作次數. 下來M行操作
【輸出】:有詢問的時候輸出
Sample Input
2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2
Sample Output
2
1
雖然說這題oj上面有標解還有標解的程式碼。。
但是昨天標解被hack了
方法就是將他的序列剛好弄成1,2,1,2,1,2,1,2,那麼他的c就幾乎沒有任何用處了。。
換句活說,標解就是一個暴力+玄學優化。。
資料水的話能過。。但是要是上面這個的話,就被卡成
據說跑了幾十秒才跑出來,超時到爆炸。。
於是就開始思考有沒有更好的方法。。
一開始想的是待修改的莫隊,然而這個複雜度肯定過不去
那麼還是迴歸線段樹吧
我們考慮對序列的每一個點都建一個bitset,不會的點這裡,然後維護就是兩個bitset或一下就好了。。
由於是一段修改,於是我們要打lazy,不打會T
時間複雜度的話是O(nlogn*50/32),感覺這個複雜度就可以過了吧。。至少比標解靠譜很多。。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<bitset>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1000005;
struct qq
{
int l,r;
int s1,s2;
bitset<51> c;
int lazy;
}s[N*2];int num=0;
int l,m;
void bt (int l,int r)
{
int a=++num;
s[a].l=l;s[a].r=r;
s[a].lazy=0;
s[a].c.reset();
s[a].c[1]=1;
if (l==r) return ;
int mid=(l+r)>>1;
s[a].s1=num+1;bt(l,mid);
s[a].s2=num+1;bt(mid+1,r);
}
void update (int x)
{
int s1=s[x].s1,s2=s[x].s2;
int lazy=s[x].lazy;s[x].lazy=0;
s[s1].c.reset();s[s1].c[lazy]=1;s[s1].lazy=lazy;
s[s2].c.reset();s[s2].c[lazy]=1;s[s2].lazy=lazy;
return ;
}
void change (int now,int l,int r,int tt)//這一段範圍都變成這個
{
if (s[now].l==l&&s[now].r==r)
{
s[now].c.reset();
s[now].c[tt]=1;
s[now].lazy=tt;
return ;
}
if (s[now].lazy!=0) update(now);
int s1=s[now].s1,s2=s[now].s2;
int mid=(s[now].l+s[now].r)>>1;
if (r<=mid) change(s1,l,r,tt);
else if (l>mid) change(s2,l,r,tt);
else change(s1,l,mid,tt),change(s2,mid+1,r,tt);
s[now].c=(s[s[now].s1].c|s[s[now].s2].c);
return ;
}
bitset<51> ans;
void solve (int now,int l,int r)
{
if (s[now].l==l&&s[now].r==r)
{
ans=(ans|s[now].c);
return ;
}
if (s[now].lazy!=0)update(now);
int s1=s[now].s1,s2=s[now].s2;
int mid=(s[now].l+s[now].r)>>1;
if (r<=mid) solve(s1,l,r);
else if (l>mid) solve(s2,l,r);
else solve(s1,l,mid),solve(s2,mid+1,r);
}
int main()
{
scanf("%d%d",&l,&m);
bt(1,l);
for (int u=1;u<=m;u++)
{
char ss[5];
scanf("%s",ss);
if (ss[0]=='C')
{
int l,r,tt;
scanf("%d%d%d",&l,&r,&tt);
if (l>r) swap(l,r);
change(1,l,r,tt);
}
else
{
ans.reset();
int l,r;
scanf("%d%d",&l,&r);
if (l>r) swap(l,r);
solve(1,l,r);
printf("%d\n",ans.count());
}
}
return 0;
}