統計顏色 線段樹(狀態壓縮)
阿新 • • 發佈:2019-02-02
時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 32768K,其他語言65536K
64bit IO Format: %lld
題目描述
n個桶按順序排列,我們用1~n給桶標號。有兩種操作:
1 l r c 區間[l,r]中的每個桶中都放入一個顏色為c的球 (1≤l,r ≤n,l≤r,0≤c≤60)
2 l r 查詢區間[l,r]的桶中有多少種不同顏色的球 (1≤l,r ≤n,l≤r)
輸入描述:
有多組資料,對於每組資料:
第一行有兩個整數n,m(1≤n,m≤100000)
接下來m行,代表m個操作,格式如題目所示。
輸出描述:
對於每個2號操作,輸出一個整數,表示查詢的結果。
示例1
輸入
10 10
1 1 2 0
1 3 4 1
2 1 4
1 5 6 2
2 1 6
1 7 8 1
2 3 8
1 8 10 3
2 1 10
2 3 8
輸出
2
3
2
4
3
解題思路:longlong 有63位 每一個節點我們用一個longlong 型別的數字記錄是否有該球(按位或),區間滿足按位或,
這樣每個節點就不用開一個數組來記錄球的種類個數,並且區間合併也更快了。
#include<bits/stdc++.h> using namespace std; #define LL long long #define N 100005 struct node { LL cnt; LL sum; }t[N*4]; void push_up(int rt) { t[rt].sum = t[rt<<1].sum|t[rt<<1|1].sum; } void push_down(int rt) { if(t[rt].cnt) { LL tmp=t[rt].cnt; t[rt<<1].cnt |= tmp; t[rt<<1|1].cnt |= tmp; t[rt<<1].sum |= tmp; t[rt<<1|1].sum |= tmp; t[rt].cnt=0; } } void add(int rt,int l,int r,int ql,int qr,LL k) { if(l>=ql && r<=qr) { t[rt].cnt|=k; t[rt].sum|=k; return ; } push_down(rt); int m=(l+r)>>1; if(ql<=m) add(rt<<1,l,m,ql,qr,k); if(qr>m) add(rt<<1|1,m+1,r,ql,qr,k); push_up(rt); } LL query(int rt,int l,int r,int ql,int qr) { if(l>=ql && r<=qr) { return t[rt].sum; } push_down(rt); int m=(l+r)>>1; LL ans=0; if(ql<=m) ans|=query(rt<<1,l,m,ql,qr); if(qr>m) ans|=query(rt<<1|1,m+1,r,ql,qr); return ans; } int main() { int n,m; while(cin>>n>>m) { memset(t,0,sizeof(t)); int f,x,y,c; for(int i=0;i<m;i++) { scanf("%d",&f); if(f==1) { scanf("%d%d%d",&x,&y,&c); add(1,1,n,x,y,(1LL<<c)); } if(f==2) { scanf("%d%d",&x,&y); LL ans=query(1,1,n,x,y); int s=0; while(ans) { if(ans&1)s++; ans>>=1; } printf("%d\n",s); } } } return 0; }