[hdu 6315] Naive Operations 线段树+思维 2018多校2

【题目】

题目链接

| Time Limit: 6000/3000 MS (Java/Others) |
| Memory Limit: 502768/502768 K (Java/Others) |

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 ∑ r i=l ⌊ai/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.
1≤n,q≤100000, 1≤l≤r≤n, 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

【题意】
两列数字a列初始为0,b列给定,可进行两种操作
1.把区间l到r的的a列数字加1
2.询问 l到r区间 ai/bi 下取整值 的和

【题解】

  • 一些错误思路:一开始想线段树维护区间和,然后处理每个节点对应的bi,后来发现不行。因为对每个节点都单独下取整,当成一个整体后就会有错
  • 正解:
    一个节点对答案贡献增加1,就说名这个节点被加过了bi词。倒着想,每个节点值v开始为b,每次1操作,v--,减到0的时候这个值的ans+1,v重新置为b。
    然后维护一个区间最小值,如果当前最小值-1还不到0,可以不用向下操作;设置一个lazy标记,当前点减了但是儿子结点还没减的值。如果当前节点最小值为1了,就要向下递归更改。
    到叶子节点了,如果v减到0了,v重设成b,ans++。

这个倒着想来处理下取整的方法可太机智了,,,我自己没想到这样维护。

【AC代码】

#include<bits/stdc++.h>
using namespace std;
#define ln (node<<1)
#define rn (node<<1)|1
#define len  r-l+1
int const maxn=100005;
int b[maxn],z[maxn<<2],lazy[maxn<<2],sum[maxn<<2],lrange,rrange,ans;
int n,q;
void add(int l,int r,int node,int x){
	lazy[node]+=x;
	z[node]-=x;
}
void pushdown(int l,int r,int node){//改为当前节点对,对下面的打标记
	if(!lazy[node])return ;
	int mid=(l+r)>>1;
	add(l,mid,ln,lazy[node]);
	add(mid+1,r,rn,lazy[node]);
	lazy[node]=0;
}
void update(int l,int r,int node){
	sum[node]=sum[ln]+sum[rn];
	z[node]=min(z[ln],z[rn]);
}
void change(int l,int r,int node){
	if(l>=lrange&&r<=rrange&&z[node]!=1){
		lazy[node]++;
		z[node]--;
		return ;
	}
	else if(l==r&&z[node]==1){
		z[node]=b[l];sum[node]++;lazy[node]=0;
		return ;
	}
	int mid=(l+r)>>1;
	pushdown(l,r,node);
	if(lrange<=mid)change(l,mid,ln);
	if(mid<rrange)change(mid+1,r,rn);
	update(l,r,node);
}
void query(int l,int r,int node){
	pushdown(l,r,node);
	if(l>=lrange&&r<=rrange){
		ans+=sum[node];
		return;
	}
	int mid=(l+r)>>1;
	if(lrange<=mid)query(l,mid,ln);
	if(mid+1<=rrange)query(mid+1,r,rn);
}
inline int get_num(){
	int num=0;
	char ch;
	bool flag=false;
	ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')flag=true; ch=getchar();}
	while(ch>='0'&&ch<='9'){num=(num<<1)+(num<<3)+ch-'0';ch=getchar();}
	if(flag)return num*-1;
	return num;
}
void built(int l,int r,int node){
	if(l==r){
		z[node]=b[l];return ;
	}
	int mid=(l+r)>>1;
	built(l,mid,ln);
	built(mid+1,r,rn);
	z[node]=min(z[ln],z[rn]);
}
int main(){
	while(scanf("%d%d",&n,&q)!=EOF){
		for(int i=1;i<=n;i++)b[i]=get_num();
		built(1,n,1);
		int m=n<<2;//记得初始化,把lazy也清0
		for(int i=1;i<=m;i++)lazy[i]= 0,sum[i]=0;
		string s;
		for(int k=1;k<=q;k++){
			cin>>s;
			lrange=get_num();rrange=get_num();
			if(s[0]=='a'){
				change(1,n,1);
			}
			else{
				ans=0;
				query(1,n,1);
				printf("%d\n",ans);
			}
		}
	}
	return 0;
}
posted @ 2020-02-04 23:38  conver^_^  阅读(140)  评论(0编辑  收藏  举报