BZOJ5334 [TJOI2018] 数学计算 【线段树分治】

本文介绍了一种使用线段树分治算法解决特定问题的方法。针对包含加入和删除操作的问题,通过建立时间线段树来高效更新受影响节点,并最终将所有标记下传。此算法的时间复杂度为O(nlogn),适用于mod非质数的情况。

题目分析:

  大概是考场上的签到题。首先mod不是质数,所以不能求逆元。注意到有加入操作和删除操作。一个很典型的想法就是线段树分治。建立时间线段树然后只更改有影响的节点,最后把所有标记下传。时间复杂度是O(nlogn)。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int q,mod;
 5 
 6 int data[405000];
 7 struct node{int l,r,d;}p[102000];
 8 
 9 void read(){
10     memset(p,0,sizeof(p));
11     memset(data,0,sizeof(data));
12     scanf("%d%d",&q,&mod);
13     for(int i=1;i<=q;i++){
14     int cas; scanf("%d",&cas);
15     int x; scanf("%d",&x);
16     if(cas == 1){
17         p[i].l = i;p[i].d = x;
18     }else{p[x].r = i;}
19     }
20 }
21 
22 void add(int now,int tl,int tr,int l,int r,int d){
23     if(tl >= l && tr <= r){
24     data[now] = (1ll*data[now]*d)%mod;
25     return;
26     }
27     if(tl > r || tr < l) return;
28     int mid = (tl+tr)/2;
29     add(now<<1,tl,mid,l,r,d);
30     add(now<<1|1,mid+1,tr,l,r,d);
31 }
32 
33 void dfs(int now,int tl,int tr){
34     if(tl == tr){printf("%d\n",data[now]);return;}
35     int L = now*2,R = now*2+1;
36     data[L] = (1ll*data[L]*data[now])%mod;
37     data[R] = (1ll*data[R]*data[now])%mod;
38     data[now] = 1;int mid =(tl+tr)/2;
39     dfs(L,tl,mid); dfs(R,mid+1,tr);
40 }
41 
42 void work(){
43     for(int i=1;i<=4*q;i++) data[i] = 1;
44     for(int i=1;i<=q;i++){
45     if(p[i].l == 0) continue;
46     if(p[i].r == 0) add(1,1,q,p[i].l,q,p[i].d);
47     else add(1,1,q,p[i].l,p[i].r-1,p[i].d);
48     }
49     dfs(1,1,q);
50 }
51 
52 int main(){
53     int t; scanf("%d",&t);
54     while(t--){
55     read();
56     work();
57     }
58     return 0;
59 }

 

转载于:https://www.cnblogs.com/Menhera/p/9059939.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值