HDU6315 Naive Operations(多校第二场1007)(线段树)

Naive Operations

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 502768/502768 K (Java/Others)
Total Submission(s): 3636    Accepted Submission(s): 1612


Problem Description
In a galaxy far, far away, there are two integer sequence a and b of length n.
b is a static permutation of 1 to n. Initially a is filled with zeroes.
There are two kind of operations:
1. add l r: add one for al,al+1...ar
2. query l r: query ri=lai/bi
 

 

Input
There are multiple test cases, please read till the end of input file.
For each test case, in the first line, two integers n,q, representing the length of a,b and the number of queries.
In the second line, n integers separated by spaces, representing permutation b.
In the following q lines, each line is either in the form 'add l r' or 'query l r', representing an operation.
1n,q100000, 1lrn, there're no more than 5 test cases.
 

 

Output
Output the answer for each 'query', each one line.
 

 

Sample Input
5 12 1 5 2 4 3 add 1 4 query 1 4 add 2 5 query 2 5 add 3 5 query 1 5 add 2 4 query 1 4 add 2 5 query 2 5 add 2 2 query 1 5
 

 

Sample Output
1 1 2 4 4 6
 
 
 
题目大意:b[1-n] 是 1-n  ,a[1-n] 是 0,add区间每一数加1,query区间a[i]/b[i]的和
 
 
思路:维护区间最小值,add操作为b[l]~b[r] 减一,最小值为0说明某个位置a[i]/b[i]=1, 答案贡献1,最后求区间和即可
 
 
  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <math.h>
  4 #include <string.h>
  5 #include <stdlib.h>
  6 #include <string>
  7 #include <vector>
  8 #include <set>
  9 #include <map>
 10 #include <queue>
 11 #include <algorithm>
 12 #include <sstream>
 13 #include <stack>
 14 using namespace std;
 15 #define rep(i,a,n) for (int i=a;i<n;i++)
 16 #define per(i,a,n) for (int i=n-1;i>=a;i--)
 17 #define pb push_back
 18 #define mp make_pair
 19 #define all(x) (x).begin(),(x).end()
 20 #define fi first
 21 #define se second
 22 #define SZ(x) ((int)(x).size())
 23 #define FO freopen("in.txt", "r", stdin);
 24 #define debug(x) cout << "&&" << x << "&&" << endl;
 25 #define lowbit(x) (x&-x)
 26 #define mem(a,b) memset(a, b, sizeof(a));
 27 typedef vector<int> VI;
 28 typedef long long ll;
 29 typedef pair<int,int> PII;
 30 const ll mod=1000000007;
 31 const int inf = 0x3f3f3f3f;
 32 ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
 33 ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
 34 //head
 35 
 36 const int N=100010;
 37 int b[N];
 38 int sum[N<<2],sub[N<<2],lazy[N<<2];//区间和  区间最小值 lazy标记
 39 
 40 void Pushup(int rt) {//上传 
 41     sum[rt]=sum[rt<<1]+sum[rt<<1|1];//左右孩子之和
 42     sub[rt]=min(sub[rt<<1],sub[rt<<1|1]);//左右孩子的最小值
 43 }
 44 
 45 void Pushdown(int rt) {//下压 
 46     lazy[rt<<1]+=lazy[rt];//传标记
 47     lazy[rt<<1|1]+=lazy[rt];
 48     sub[rt<<1]-=lazy[rt];//更新 因为是每次减一 所以就直接减lazy
 49     sub[rt<<1|1]-=lazy[rt];
 50     lazy[rt]=0;//清除父节点标记
 51 }
 52 
 53 void build(int rt,int L,int R) {
 54     sum[rt]=0;//rt的初始状态
 55     lazy[rt]=0;
 56     if(L==R) {
 57         scanf("%d",&b[L]);//建树的一种方式
 58         sub[rt]=b[L];
 59         return;
 60     }
 61     int mid=(L+R)>>1;//递归建树
 62     build(rt<<1,L,mid);
 63     build(rt<<1|1,mid+1,R);
 64     Pushup(rt);//因为不涉及修改,不需要下压,只需上传
 65 }
 66 
 67 void dfs(int rt,int L,int R) {
 68     if(L==R) {
 69         sum[rt]++;
 70         sub[rt]=b[L];
 71         return;
 72     }
 73     int mid=(L+R)>>1;
 74     Pushdown(rt);
 75     if(!sub[rt<<1]) dfs(rt<<1,L,mid);
 76     if(!sub[rt<<1|1]) dfs(rt<<1|1,mid+1,R);
 77     Pushup(rt);
 78 }
 79 
 80 void Updata(int rt,int L,int R,int l,int r) {//L,R为时时变动的区间
 81     if(L>=l&&R<=r) {//如果当前节点在待查询节点内
 82         lazy[rt]++;
 83         sub[rt]--;
 84         if(!sub[rt]) dfs(rt,L,R);//如果区间最小值为0,递归搜索位置
 85         return;
 86     }
 87     int mid=(L+R)>>1;//递归找l,r的涉及区间
 88     Pushdown(rt);//需要走左右孩子,先下压
 89     if(l<=mid) Updata(rt<<1,L,mid,l,r);
 90     if(r>mid) Updata(rt<<1|1,mid+1,R,l,r);
 91     Pushup(rt);//走完之后,状态上传给父亲节点
 92 }
 93 
 94 int Query(int rt,int L,int R,int l,int r) {
 95     if(L>=l&&R<=r) //待查询区间内
 96         return sum[rt];
 97     int mid=(L+R)>>1;
 98     Pushdown(rt);//走左右孩子
 99     int ans=0;
100     if(l<=mid) ans+=Query(rt<<1,L,mid,l,r);
101     if(r>mid) ans+=Query(rt<<1|1,mid+1,R,l,r);
102     Pushup(rt);//走完,状态上传给父亲节点
103     return ans;
104 }
105 
106 
107 int main() {
108     int n,q;
109     while(~scanf("%d%d",&n,&q)) {
110         build(1,1,n);
111         char s[10];
112         int a,b;
113         while(q--) {
114             scanf("%s%d%d",s,&a,&b);
115             if(s[0]=='a') Updata(1,1,n,a,b);
116             else printf("%d\n",Query(1,1,n,a,b));
117         }
118     }
119 }

 

上面用了dfs搜索最小值为0的位置,也可以一直去找。

 

 1 void Update(int L,int R,int l,int r,int rt)
 2 {
 3     if(a[rt]>1&&L<=l&&r<=R)
 4     {
 5         lazy[rt]++;
 6         a[rt]--;
 7         return;
 8     }
 9     if(a[rt]==1&&l==r)
10     {
11         sum[rt]++;
12         lazy[rt]=0;
13         a[rt]=b[l];
14         return;
15     }
16     int mid=(l+r)>>1;
17     PushDown(rt);
18     if(L<=mid)Update(L,R,l,mid,rt<<1);
19     if(R>mid)Update(L,R,mid+1,r,rt<<1|1);
20     PushUp(rt);
21 }

!!!!这里的变量含义和第一个代码不一样。自行理解。

 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值