zoukankan      html  css  js  c++  java
  • JZOJ 3494. 【NOIP2013模拟联考13】线段(segment)

    题目

    数轴上有很多单位线段,一开始时所有单位线段的权值都是 (1)。有两种操作,第一种操作将某一区间内的单位线段权值乘以 (w),第二种操作将某一区间内的单位线段权值取 (w) 次幂。并且你还需要回答一些询问,每个询问需要求出某一区间的单位线段权值之积。由于答案可能很大,你只需要求出答案 (mod (10^9+7)) 的值。
    说明:(n) 个点只有 (n-1) 条线段。

    分析

    线段树懒标记基本操作
    幂运算优先,然后乘法运算
    对于 ([-10^9,10^9]) 的操作区间,直接动态开点就好了
    离散化随你
    注意:介于操作数乘起来很大,指数是不能随便取模的,所以我们需要扩展欧拉定理
    即:

    [a^c equiv a^{c \% varphi(m)} exttt{ gcd(a,m)=1} \ a^c equiv a^c exttt{ gcd(a,m)!=1 && c<m} \ a^c equiv a^{c \% varphi(m)+varphi(m)} exttt{ gcd(a,m)!=1 && c>m} ]

    (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
    " , seg_query(Ml , Mr , 1 , l , r));
    	}
    }
    
  • 相关阅读:
    2017年系统架构设计师论文范文
    在SQL Server 2008中执行透明数据加密(转自IT专家网)
    开发笔记
    [置顶] GO-Gin框架快速指南
    [置顶] JS-逆向爬虫
    [置顶] ES篇
    [置顶] GO
    [置顶] 爬虫入狱指南
    [置顶] websocket
    [置顶] Linux篇
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/14049890.html
Copyright © 2011-2022 走看看