Codevs 4927 线段树练习5(分块)

2023-12-25 15:58
文章标签 练习 线段 codevs 分块 4927

本文主要是介绍Codevs 4927 线段树练习5(分块),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

4927 线段树练习5
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 黄金 Gold
题目描述 Description
有n个数和5种操作
add a b c:把区间[a,b]内的所有数都增加c
set a b c:把区间[a,b]内的所有数都设为c
sum a b:查询区间[a,b]的区间和
max a b:查询区间[a,b]的最大值
min a b:查询区间[a,b]的最小值
输入描述 Input Description
第一行两个整数n,m,第二行n个整数表示这n个数的初始值
接下来m行操作,同题目描述
输出描述 Output Description
对于所有的sum、max、min询问,一行输出一个答案
样例输入 Sample Input
10 6
3 9 2 8 1 7 5 0 4 6
add 4 9 4
set 2 6 2
add 3 8 2
sum 2 10
max 1 7
min 3 6
样例输出 Sample Output
49
11
4
数据范围及提示 Data Size & Hint
10%:1

/*
分块. 
这题改了一个下午.
直接呵呵了.
思路是挺简单的,但是实现起来有点鬼畜.
哎就不说啥了 码力太弱.
注意几个细节.
重构不完整的块时要注意区间和贡献的计算还有每个位置的值应该是啥.
★x,y在同一个块中不要忘了重构y到块末的贡献.
然后区分该区间是否被"set",重构的话把标记清掉.
感谢前人的分块solution code 给了我debug一个下午的可能hhh.
*/
#include<cstdio>
#include<cmath>
#include<iostream>
#define MAXN 200001
#define MAXM 200001
#define LL long long
#define INF 1e18
using namespace std;
int n,m,q,belong[MAXN];
LL ans,s[MAXN],sum[MAXM],tot,tag[MAXM],bj[MAXM],max1[MAXM],min1[MAXM];
bool b[MAXM];
LL read()
{LL x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();return x*f;
}
void sloveadd(int x,int y,LL z)
{for(int i=x;i<=min(belong[x]*m,y);i++) {if(b[belong[x]]) s[i]=bj[belong[x]]+tag[belong[x]]+z;else s[i]+=z+tag[belong[x]];sum[belong[x]]+=z;}if(belong[x]==belong[y]){for(int i=y+1;i<=belong[y]*m;i++){if(b[belong[y]]) s[i]=bj[belong[y]]+tag[belong[y]];else s[i]+=tag[belong[y]];}}for(int i=(belong[x]-1)*m+1;i<=x-1;i++){if(b[belong[x]]) s[i]=bj[belong[x]]+tag[belong[x]];else s[i]+=tag[belong[x]];}b[belong[x]]=false;tag[belong[x]]=0;max1[belong[x]]=-INF,min1[belong[x]]=INF;for(int i=(belong[x]-1)*m+1;i<=min(n,belong[x]*m);i++){max1[belong[i]]=max(max1[belong[i]],s[i]+tag[belong[i]]);min1[belong[i]]=min(min1[belong[i]],s[i]+tag[belong[i]]);}for(int i=belong[x]+1;i<=belong[y]-1;i++) sum[i]+=z*m,tag[i]+=z,max1[i]+=z,min1[i]+=z;if(belong[x]!=belong[y]){for(int i=(belong[y]-1)*m+1;i<=y;i++) {if(b[belong[y]]) s[i]=bj[belong[y]]+tag[belong[y]]+z;else s[i]+=z+tag[belong[y]];sum[belong[y]]+=z;}for(int i=y+1;i<=min(n,belong[y]*m);i++){if(b[belong[y]]) s[i]=bj[belong[y]]+tag[belong[y]];else s[i]+=tag[belong[y]];}max1[belong[y]]=-INF,min1[belong[y]]=INF;b[belong[y]]=false;tag[belong[y]]=0;max1[belong[y]]=-INF,min1[belong[y]]=INF;for(int i=(belong[y]-1)*m+1;i<=min(n,belong[y]*m);i++){max1[belong[y]]=max(max1[belong[y]],s[i]+tag[belong[y]]);min1[belong[y]]=min(min1[belong[y]],s[i]+tag[belong[y]]);}}return ;
}
void slovechange(int x,int y,LL z)
{for(int i=x;i<=min(belong[x]*m,y);i++) {if(!b[belong[x]]) sum[belong[x]]+=z-s[i]-tag[belong[x]];else sum[belong[x]]+=z-bj[belong[x]]-tag[belong[x]];s[i]=z;}if(belong[x]==belong[y]){for(int i=y+1;i<=belong[y]*m;i++){if(b[belong[y]]) s[i]=bj[belong[y]]+tag[belong[y]];else s[i]+=tag[belong[y]];}}for(int i=(belong[x]-1)*m+1;i<=x-1;i++){if(b[belong[x]]) s[i]=bj[belong[x]]+tag[belong[x]];else s[i]+=tag[belong[x]];}b[belong[x]]=false;tag[belong[x]]=0;max1[belong[x]]=-INF,min1[belong[x]]=INF;for(int i=(belong[x]-1)*m+1;i<=min(n,belong[x]*m);i++){max1[belong[i]]=max(max1[belong[i]],s[i]+tag[belong[i]]);min1[belong[i]]=min(min1[belong[i]],s[i]+tag[belong[i]]);}for(int i=belong[x]+1;i<=belong[y]-1;i++)sum[i]=z*m,tag[i]=0,b[i]=true,max1[i]=z,min1[i]=z,bj[i]=z;if(belong[x]!=belong[y]){for(int i=(belong[y]-1)*m+1;i<=y;i++) {if(!b[belong[y]]) sum[belong[y]]+=z-s[i]-tag[belong[y]];else sum[belong[y]]+=z-bj[belong[y]]-tag[belong[y]];s[i]=z;}for(int i=y+1;i<=min(n,belong[y]*m);i++){if(b[belong[y]]) s[i]=bj[belong[y]]+tag[belong[y]];else s[i]+=tag[belong[y]];}b[belong[y]]=false;tag[belong[y]]=0;max1[belong[y]]=-INF,min1[belong[y]]=INF;for(int i=(belong[y]-1)*m+1;i<=min(n,belong[y]*m);i++){max1[belong[y]]=max(max1[belong[y]],s[i]+tag[belong[y]]);min1[belong[y]]=min(min1[belong[y]],s[i]+tag[belong[y]]);}}return ;
}
LL slovequerysum(int x,int y)
{ans=0;for(int i=x;i<=min(belong[x]*m,y);i++){if(!b[belong[x]]) ans+=s[i]+tag[belong[i]];else ans+=bj[belong[i]]+tag[belong[i]];}for(int i=belong[x]+1;i<=belong[y]-1;i++) ans+=sum[i];if(belong[x]!=belong[y]){for(int i=(belong[y]-1)*m+1;i<=y;i++){if(!b[belong[y]]) ans+=s[i]+tag[belong[y]];else ans+=bj[belong[y]]+tag[belong[y]];}}return ans;
}
LL slovequerymax(int x,int y)
{ans=-INF;for(int i=x;i<=min(belong[x]*m,y);i++){if(!b[belong[x]]) ans=max(ans,s[i]+tag[belong[i]]);else ans=max(ans,bj[belong[i]]+tag[belong[i]]);}for(int i=belong[x]+1;i<=belong[y]-1;i++) ans=max(ans,max1[i]);if(belong[x]!=belong[y]){for(int i=(belong[y]-1)*m+1;i<=y;i++){if(!b[belong[y]]) ans=max(ans,s[i]+tag[belong[y]]);else ans=max(ans,bj[belong[y]]+tag[belong[y]]);}}return ans;
}
LL slovequerymin(int x,int y)
{ans=INF;for(int i=x;i<=min(belong[x]*m,y);i++){if(!b[belong[x]]) ans=min(ans,s[i]+tag[belong[i]]);else ans=min(ans,bj[belong[i]]+tag[belong[i]]);}for(int i=belong[x]+1;i<=belong[y]-1;i++) ans=min(ans,min1[i]);if(belong[x]!=belong[y]){for(int i=(belong[y]-1)*m+1;i<=y;i++){if(!b[belong[y]]) ans=min(ans,s[i]+tag[belong[y]]);else ans=min(ans,bj[belong[y]]+tag[belong[y]]);}}return ans;
}
int main()
{int x,y,z;LL k;char ch[6];n=read();q=read();m=sqrt(n);for(int i=1;i<=n;i++) belong[i]=(i-1)/m+1;for(int i=1;i<=belong[n];i++) max1[i]=-INF,min1[i]=INF;for(int i=1;i<=n;i++){s[i]=read(),sum[belong[i]]+=s[i];max1[belong[i]]=max(max1[belong[i]],s[i]);min1[belong[i]]=min(min1[belong[i]],s[i]);}while(q--){scanf("%s",ch);x=read(),y=read();if(ch[0]=='a') k=read(),sloveadd(x,y,k);else if(ch[1]=='e') k=read(),slovechange(x,y,k);else if(ch[1]=='u') printf("%lld\n",slovequerysum(x,y));else if(ch[1]=='a') printf("%lld\n",slovequerymax(x,y));else if(ch[1]=='i') printf("%lld\n",slovequerymin(x,y));}return 0;
}

这篇关于Codevs 4927 线段树练习5(分块)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/536075

相关文章

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

hdu1689(线段树成段更新)

两种操作:1、set区间[a,b]上数字为v;2、查询[ 1 , n ]上的sum 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdl

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

poj 1127 线段相交的判定

题意: 有n根木棍,每根的端点坐标分别是 px, py, qx, qy。 判断每对木棍是否相连,当他们之间有公共点时,就认为他们相连。 并且通过相连的木棍相连的木棍也是相连的。 解析: 线段相交的判定。 首先,模板中的线段相交是不判端点的,所以要加一个端点在直线上的判定; 然后,端点在直线上的判定这个函数是不判定两个端点是同一个端点的情况的,所以要加是否端点相等的判断。 最后

HDU4737线段树

题目大意:给定一系列数,F(i,j)表示对从ai到aj连续求或运算,(i<=j)求F(i,j)<=m的总数。 const int Max_N = 100008 ;int sum[Max_N<<2] , x[Max_N] ;int n , m ;void push_up(int t){sum[t] = sum[t<<1] | sum[t<<1|1] ;}void upd

zoj 1721 判断2条线段(完全)相交

给出起点,终点,与一些障碍线段。 求起点到终点的最短路。 枚举2点的距离,然后最短路。 2点可达条件:没有线段与这2点所构成的线段(完全)相交。 const double eps = 1e-8 ;double add(double x , double y){if(fabs(x+y) < eps*(fabs(x) + fabs(y))) return 0 ;return x + y ;

RabbitMQ练习(AMQP 0-9-1 Overview)

1、What is AMQP 0-9-1 AMQP 0-9-1(高级消息队列协议)是一种网络协议,它允许遵从该协议的客户端(Publisher或者Consumer)应用程序与遵从该协议的消息中间件代理(Broker,如RabbitMQ)进行通信。 AMQP 0-9-1模型的核心概念包括消息发布者(producers/publisher)、消息(messages)、交换机(exchanges)、

圆与线段的交点

poj 3819  给出一条线段的两个端点,再给出n个圆,求出这条线段被所有圆覆盖的部分占了整条线段的百分比。 圆与线段的交点 : 向量AB 的参数方程  P = A + t * (B - A)      0<=t<=1 ; 将点带入圆的方程即可。  注意: 有交点 0 <= t <= 1 ; 此题求覆盖的部分。 则 若求得 t  满足 ; double ask(d