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

Posted acmerszl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
",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 }

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

 
 

以上是关于HDU6315 Naive Operations(多校第二场1007)(线段树)的主要内容,如果未能解决你的问题,请参考以下文章

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

[HDU6315]Naive Operations(线段树+树状数组)

HDU-DuoXiao第二场hdu 6315 Naive Operations 线段树

HDU6315 Naive Operations(线段树 复杂度分析)

Naive Operations HDU6315 (杭电多校2G)

HDU - 6315(2018 Multi-University Training Contest 2) Naive Operations (线段树区间操作)