1. 程式人生 > >[caioj]1100: [視訊]線段樹2(統計不同顏色)

[caioj]1100: [視訊]線段樹2(統計不同顏色)

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就幾乎沒有任何用處了。。
換句活說,標解就是一個暴力+玄學優化。。
資料水的話能過。。但是要是上面這個的話,就被卡成O(n2)了。。
據說跑了幾十秒才跑出來,超時到爆炸。。

於是就開始思考有沒有更好的方法。。
一開始想的是待修改的莫隊,然而這個複雜度肯定過不去
那麼還是迴歸線段樹吧
我們考慮對序列的每一個點都建一個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; }