• 数学计算(TJOI2018)-线段树分治


    Description

    小豆现在有一个数 x ,初始值为 1 。 小豆有 Q 次操作,操作有两种类型:
    1 m: x=x*m ,输出 x mod M ;
    2 pos: x=x/ 第 pos 次操作所乘的数(保证第 pos 次操作一定为类型 1,对于每一个类型 1 的操作至多会被除一次),输出 x mod M 。

    Input

    一共有 t 组输入。
    对于每一组输入,第一行是两个数字 Q,M 。
    接下来 Q 行,每一行为操作类型 op ,操作编号或所乘的数字 m (保证所有的输入都是合法的)。

    Output

    对于每一个操作,输出一行,包含操作执行后的 x mod M 的值

    Sample Input

    1
    10 1000000000
    1 2
    2 1
    1 2
    1 10
    2 3
    2 4
    1 6
    1 7
    1 12
    2 7

    Sample Output

    2
    1
    2
    20
    10
    1
    6
    42
    504
    84


    wtcl
    “首先mod不是质数,所以不能求逆元。”
    因为忘了这句话而导致花了一小时思考为什么不能暴力。。。

    • 注意到有加入操作和删除操作,一个很典型的想法就是线段树分治。
    • 线段树分治:具有插入删除操作的信息影响的都是一个个时间区间,可以使用线段树来记录其覆盖的影响区间,并在其上通过标记的方式进行记录。

    代码

    #include <iostream>
    #include <cstdio>
    #define int long long
    using namespace std;
    const int maxn=100003;
    int q,mod;
    struct node{int l,r,mul;}a[maxn<<2];
    struct node2{int lef,rig,val;}keep[maxn];
    void build(int x,int left,int right)
    {
    	a[x].l=left,a[x].r=right,a[x].mul=1;
    	if(left==right) return;
    	int mid=left+right>>1;
    	build(x<<1,left,mid),build(x<<1|1,mid+1,right);
    }
    void add(int x,int left,int right,int d)
    {
    	if(a[x].r<left||a[x].l>right) return;
    	if(left<=a[x].l&&right>=a[x].r) return a[x].mul=a[x].mul*d%mod,void();
    	add(x<<1,left,right,d),add(x<<1|1,left,right,d);
    }
    void dfs(int x)
    {
    	if(a[x].l==a[x].r) return cout<<a[x].mul<<'
    ',void();
    	a[x<<1].mul=a[x<<1].mul*a[x].mul%mod,dfs(x<<1);
    	a[x<<1|1].mul=a[x<<1|1].mul*a[x].mul%mod,dfs(x<<1|1);
    }
    signed main()
    {
    	freopen("tmp.in","r",stdin);
    	int T; scanf("%lld",&T);
    	while(T--)
    	{
    		scanf("%lld%lld",&q,&mod);
    		for(int i=1,opt,x;i<=q;++i)
    		{
    			keep[i]=(node2){0,0,0};
    			scanf("%lld%lld",&opt,&x);
    			if(opt==1) keep[i]=(node2){i,0,x};
    			else keep[x].rig=i;
    		}
    		build(1,1,q);
    		for(int i=1;i<=q;++i)
    		{
    			if(!keep[i].lef) continue;
    			if(!keep[i].rig) add(1,keep[i].lef,q,keep[i].val);
    			else add(1,keep[i].lef,keep[i].rig-1,keep[i].val);
    		}
    		dfs(1);
    	}
    	return 0;
    }
    
  • 相关阅读:
    在ASP.NET GridView 中使用e.CommandArgument传递参数
    循环处理之while and do while
    MzTreeView(梅花雪)完全攻略
    FreeTextBox使用详解
    委托、线程的用法
    Master Theorem
    python jsonpath 语法总结
    python + zmail 邮件发送
    python的yaml语法
    unittest单元测试框架总结
  • 原文地址:https://www.cnblogs.com/wuwendongxi/p/14545878.html
Copyright © 2020-2023  润新知