JZOJ 3494. 【NOIP2013模擬聯考13】線段(segment)
阿新 • • 發佈:2020-11-27
題目
數軸上有很多單位線段,一開始時所有單位線段的權值都是 \(1\)。有兩種操作,第一種操作將某一區間內的單位線段權值乘以 \(w\),第二種操作將某一區間內的單位線段權值取 \(w\) 次冪。並且你還需要回答一些詢問,每個詢問需要求出某一區間的單位線段權值之積。由於答案可能很大,你只需要求出答案 \(mod (10^9+7)\) 的值。
說明:\(n\) 個點只有 \(n-1\) 條線段。
分析
線段樹懶標記基本操作
冪運算優先,然後乘法運算
對於 \([-1^9,1^9]\) 的操作區間,直接動態開店就好了
離散化隨你
\(Code\)
#include<cstdio> #define LL long long using namespace std; const int N = 2e6 + 5 , Ml = -1e9 , Mr = 1e9; const LL P = 1e9 + 7 , phi = 1e9 + 6; int n , sz = 1; struct segment{ LL sum , tg1 , tg2; int ls , rs; }seg[N]; LL fpow(LL x , LL y) { LL res = 1; for(; y; y >>= 1) { if (y & 1) res = res * x % P; x = x * x % P; } return res; } void New(int k , int o) { if (!o) { if (!seg[k].ls) seg[seg[k].ls = ++sz] = segment{1 , 1 , 1 , 0 , 0}; } else { if (!seg[k].rs) seg[seg[k].rs = ++sz] = segment{1 , 1 , 1 , 0 , 0}; } } void pushup(int k) { seg[k].sum = seg[seg[k].ls].sum * seg[seg[k].rs].sum % P; } void pushdown(int k , int l , int r) { if (seg[k].tg2 != 1) { New(k , 0) , New(k , 1); seg[seg[k].ls].sum = fpow(seg[seg[k].ls].sum , seg[k].tg2); seg[seg[k].rs].sum = fpow(seg[seg[k].rs].sum , seg[k].tg2); seg[seg[k].ls].tg2 = seg[seg[k].ls].tg2 * seg[k].tg2 % phi; seg[seg[k].rs].tg2 = seg[seg[k].rs].tg2 * seg[k].tg2 % phi; seg[seg[k].ls].tg1 = fpow(seg[seg[k].ls].tg1 , seg[k].tg2); seg[seg[k].rs].tg1 = fpow(seg[seg[k].rs].tg1 , seg[k].tg2); seg[k].tg2 = 1; } if (seg[k].tg1 != 1) { int mid = (l + r) >> 1; New(k , 0) , New(k , 1); seg[seg[k].ls].sum = seg[seg[k].ls].sum * fpow(seg[k].tg1 , mid - l + 1) % P; seg[seg[k].rs].sum = seg[seg[k].rs].sum * fpow(seg[k].tg1 , r - mid) % P; seg[seg[k].ls].tg1 = seg[seg[k].ls].tg1 * seg[k].tg1 % P; seg[seg[k].rs].tg1 = seg[seg[k].rs].tg1 * seg[k].tg1 % P; seg[k].tg1 = 1; } } void seg_mul(int l , int r , int k , int x , int y , int z) { if (x <= l && r <= y) { seg[k].sum = seg[k].sum * fpow(z , r - l + 1) % P; seg[k].tg1 = seg[k].tg1 * z % P; return; } pushdown(k , l , r); int mid = (l + r) >> 1; if (x <= mid) New(k , 0) , seg_mul(l , mid , seg[k].ls , x , y , z); if (y > mid) New(k , 1) , seg_mul(mid + 1 , r , seg[k].rs , x , y , z); pushup(k); } void seg_pow(int l , int r , int k , int x , int y , int z) { if (x <= l && r <= y) { seg[k].sum = fpow(seg[k].sum , z); seg[k].tg1 = fpow(seg[k].tg1 , z) , seg[k].tg2 = seg[k].tg2 * z % phi; return; } pushdown(k , l , r); int mid = (l + r) >> 1; if (x <= mid) New(k , 0) , seg_pow(l , mid , seg[k].ls , x , y , z); if (y > mid) New(k , 1) , seg_pow(mid + 1 , r , seg[k].rs , x , y , z); pushup(k); } LL seg_query(int l , int r , int k , int x , int y) { if (x <= l && r <= y) return seg[k].sum; pushdown(k , l , r); int mid = (l + r) >> 1; LL res = 1; if (x <= mid && seg[k].ls) res = seg_query(l , mid , seg[k].ls , x , y); if (y > mid && seg[k].rs) res = res * seg_query(mid + 1 , r , seg[k].rs , x , y) % P; return res; } int main() { freopen("segment.in" , "r" , stdin); freopen("segment.out" , "w" , stdout); scanf("%d" , &n); int op , l , r , w; seg[0] = seg[1] = segment{1 , 1 , 1 , 0 , 0}; while (n--) { scanf("%d%d%d" , &op , &l , &r) , ++l; if (op == 0) scanf("%d" , &w) , seg_mul(Ml , Mr , 1 , l , r , w); else if (op == 1) scanf("%d" , &w) , seg_pow(Ml , Mr , 1 , l , r , w); else printf("%lld\n" , seg_query(Ml , Mr , 1 , l , r)); } }