传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5828
题意:三种操作,一种是区间增加,一种是区间开方,一种是区间求和。
原思路(数据已加强,这个方法已经过不了):很快能想到,如果一个100000的数字,最多开方个四五次以后,就变成1了,而且sqrt(1)=1,那么我们就可以在更新的时候想到一个很方便的剪枝,就是,如果这个区间的最大值是1,也就是这个区间全部是1的时候,就可以不继续递归下去了。
然后我就这么写了一发,结果TLE了。
但是还有一个思路可以剪枝。就是一段区间如果全部开根号到1以后,那么如果这段区间再增加值,整个区间的值就是一样的,当整个区间的值是一样的时候,只要开方一次,就能求出这个区间的值了。加了这个剪枝之后就AC了。
Update–补丁1.1(1900+ms AC):
被同学提醒了一下,在极差==1的时候,而且知道区间和,最大值和最小值的情况下,是可以直接计算出最大值和最小值的个数的,所以就可以不用在线段树里维护两个值了。就快得多了。
补丁1.0(2700+ms AC):
在昨天数据加强了以后,看到ACFun群里糖老师随手出了个数据卡掉了大部分人的程序,就是我之前的那个。
比如说:2 3 2 3 2 3这样10万个数字。然后10万次操作,(整体+6,整体sqrt)。
这个数据,我之前的程序要跑好几分钟,因为每个相邻的数字都不一样,而且整体加了以后,开方以后还是保持这样的情况,也就是说,每次操作以后,不能找到整段相等的情况。这样的话,就会一直更新下去,就非常慢。
但是我们可以思考一下,如果一个区间内的极差>1的时候,不断地进行整体加某个值然后开方,是没办法保持住这样的序列的(相邻两个极差都>1)。只有整个区间内的极差<=1的时候,才能起到这种效果。所以我们就在线段树上再增加一些信息。就是最大值和最小值,最大值的个数,最小值的个数。这样的话,如果区间内的极差==1的时候,我们也能直接对整段进行操作。就能处理前面的这种样例了。
然后在昨天的基础上考虑新情况,区间的极差==1的时候。那么这种情况开方以后有两种情况。1:整个区间相等了。2:整个区间的极差还是1。
对于第一种情况。我们只要加一个cover标记,加一个区间覆盖的标记就可以解决了。
对于第二种情况,相当于,区间减去了一个相等的值,修改一下区间增加的标记就可以了。然后在pushdown的时候增加一下cover的情况。
但是这样还是TLE,加了一个读入挂以后艰难的卡过去了。
//原思路:TLE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define mp make_pair
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define calm (l+r)>>1
const int INF = 2139062143;
const int maxn=100010;
int n,m;
struct Seg{
int mx[maxn<<2],mn[maxn<<2],tag[maxn<<2];
ll sum[maxn<<2];
inline void pushup(int rt){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
mn[rt]=min(mn[rt<<1],mn[rt<<1|1]);
}
inline void pushdown(int rt,int l,int r){
if(tag[rt]!=0){
int m=calm;
ll llen=m-l+1;
ll rlen=r-m;
tag[rt<<1]+=tag[rt];tag[rt<<1|1]+=tag[rt];
sum[rt<<1]+=tag[rt]*llen; sum[rt<<1|1]+=tag[rt]*rlen;
mx[rt<<1]+=tag[rt];mx[rt<<1|1]+=tag[rt];
mn[rt<<1]+=tag[rt];mn[rt<<1|1]+=tag[rt];
tag[rt]=0;
}
}
void print(int l,int r,int rt){
if(l==r){
printf("%I64d ",sum[rt]);
return;
}
pushdown(rt,l,r);
int m=calm;
print(lson);print(rson);
}
void build(int l,int r,int rt){
tag[rt]=0;
if(l==r){
scanf("%I64d",&sum[rt]);
mx[rt]=mn[rt]=sum[rt];
return;
}
int m=calm;
build(lson);build(rson);
pushup(rt);
}
void add(int L,int R,int v,int l,int r,int rt){
if(L<=l&&r<=R){
sum[rt]+=(ll)v*(r-l+1);
mx[rt]+=v;
mn[rt]+=v;
tag[rt]+=v;
return;
}
pushdown(rt,l,r);
int m=calm;
if(L<=m)add(L,R,v,lson);
if(R>m)add(L,R,v,rson);
pushup(rt);
}
void update(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
if(mx[rt]==1)return;
if(l==r){
sum[rt]=floor(sqrt(sum[rt]));
mx[rt]=mn[rt]=sum[rt];
return;
}
if(mx[rt]==mn[rt]){
int t=mx[rt];
mx[rt]=mn[rt]=floor(sqrt(t));
tag[rt]+=mx[rt]-t;
sum[rt]=(ll)mx[rt]*(r-l+1);
return;
}
pushdown(rt,l,r);
int m=calm;
update(L,R,lson);
update(L,R,rson);
pushup(rt);
return;
}
pushdown(rt,l,r);
int m=calm;
if(L<=m)update(L,R,lson);
if(R>m)update(L,R,rson);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return sum[rt];
}
pushdown(rt,l,r);
int m=calm;
ll ans=0;
if(L<=m)ans+=query(L,R,lson);
if(R>m)ans+=query(L,R,rson);
return ans;
}
}tree;
int main(){
//freopen("D://input.txt","r",stdin);
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
tree.build(1,n,1);
while(m--){
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
if(op==1){
int x;scanf("%d",&x);
tree.add(l,r,x,1,n,1);
}
else if(op==2){
tree.update(l,r,1,n,1);
}
else{
printf("%I64d\n",tree.query(l,r,1,n,1));
}
//tree.print(1,n,1);printf("\n");
}
}
return 0;
}
//在区间内维护两种数:AC
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define mp make_pair
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define calm (l+r)>>1
const int INF = 2139062143;
template <class T>
inline void rd(T &x) {
char c = getchar(); x = 0;while(!isdigit(c)) c = getchar();
while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
}
const int maxn=100010;
int n,m;
struct Seg{
int mx[maxn<<2],mn[maxn<<2],tag[maxn<<2],cover[maxn<<2];
ll sum[maxn<<2];
inline void pushup(int rt){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
mn[rt]=min(mn[rt<<1],mn[rt<<1|1]);
}
inline void pushdown(int rt,int l,int r){
if(cover[rt]!=0){
int m=calm;
ll llen=m-l+1;
ll rlen=r-m;
cover[rt<<1]=cover[rt<<1|1]=cover[rt];
sum[rt<<1]=(ll)cover[rt]*llen; sum[rt<<1|1]=(ll)cover[rt]*rlen;
mx[rt<<1]=mx[rt<<1|1]=mn[rt<<1]=mn[rt<<1|1]=cover[rt];
tag[rt<<1]=tag[rt<<1|1]=0;
cover[rt]=0;
}
if(tag[rt]!=0){
int m=calm;
ll llen=m-l+1;
ll rlen=r-m;
tag[rt<<1]+=tag[rt];tag[rt<<1|1]+=tag[rt];
sum[rt<<1]+=tag[rt]*llen; sum[rt<<1|1]+=tag[rt]*rlen;
mx[rt<<1]+=tag[rt];mx[rt<<1|1]+=tag[rt];
mn[rt<<1]+=tag[rt];mn[rt<<1|1]+=tag[rt];
tag[rt]=0;
}
}
void print(int l,int r,int rt){
if(l==r){
printf("%I64d ",sum[rt]);
return;
}
pushdown(rt,l,r);
int m=calm;
print(lson);print(rson);
}
void build(int l,int r,int rt){
tag[rt]=cover[rt]=0;
if(l==r){
//scanf("%I64d",&sum[rt]);
rd(sum[rt]);
mx[rt]=mn[rt]=sum[rt];
return;
}
int m=calm;
build(lson);build(rson);
pushup(rt);
}
void add(int L,int R,int v,int l,int r,int rt){
if(L<=l&&r<=R){
sum[rt]+=(ll)v*(r-l+1);
mx[rt]+=v;
mn[rt]+=v;
tag[rt]+=v;
return;
}
pushdown(rt,l,r);
int m=calm;
if(L<=m)add(L,R,v,lson);
if(R>m)add(L,R,v,rson);
pushup(rt);
}
void update(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
if(mx[rt]==1)return;
if(l==r){
sum[rt]=floor(sqrt(sum[rt]));
mx[rt]=mn[rt]=sum[rt];
return;
}
if(mx[rt]==mn[rt]){
int t=mx[rt];
mx[rt]=mn[rt]=floor(sqrt(t));
tag[rt]+=mx[rt]-t;
sum[rt]=(ll)mx[rt]*(r-l+1);
return;
}
else if(mx[rt]-mn[rt]==1){//区间极差==1的情况
int ta=mx[rt],tb=mn[rt];
int mxnum=sum[rt]-(ll)tb*(r-l+1);//直接计算出个数
int mnnum=r-l+1-mxnum;
mx[rt]=floor(sqrt(mx[rt]));
mn[rt]=floor(sqrt(mn[rt]));
if(mx[rt]-mn[rt]==1){
tag[rt]+=mx[rt]-ta;
sum[rt]=(ll)mx[rt]*mxnum+(ll)mn[rt]*mnnum;
}
else{
tag[rt]=0;cover[rt]=mx[rt];
sum[rt]=(ll)mx[rt]*(r-l+1);
}
return;
}
pushdown(rt,l,r);
int m=calm;
update(L,R,lson);
update(L,R,rson);
pushup(rt);
return;
}
pushdown(rt,l,r);
int m=calm;
if(L<=m)update(L,R,lson);
if(R>m)update(L,R,rson);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return sum[rt];
}
pushdown(rt,l,r);
int m=calm;
ll ans=0;
if(L<=m)ans+=query(L,R,lson);
if(R>m)ans+=query(L,R,rson);
return ans;
}
}tree;
int main(){
//freopen("D://input.txt","r",stdin);
int T;//scanf("%d",&T);
rd(T);
while(T--){
//scanf("%d%d",&n,&m);
rd(n);rd(m);
tree.build(1,n,1);
for(int i=1;i<=m;i++){
int op,l,r;
//scanf("%d%d%d",&op,&l,&r);
rd(op);rd(l);rd(r);
if(op==1){
int x;//scanf("%d",&x);
rd(x);
tree.add(l,r,x,1,n,1);
}
else if(op==2){
tree.update(l,r,1,n,1);
}
else{
printf("%I64d\n",tree.query(l,r,1,n,1));
}
//tree.print(1,n,1);printf("\n");
}
}
return 0;
}