点击这里送你到杭电去answer the queries
Can you answer these queries?Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 31873 Accepted Submission(s): 7608 Problem Description A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use our secret weapon to eliminate the battleships. Each of the battleships can be marked a value of endurance. For every attack of our secret weapon, it could decrease the endurance of a consecutive part of battleships by make their endurance to the square root of it original value of endurance. During the series of attack of our secret weapon, the commander wants to evaluate the effect of the weapon, so he asks you for help. Input The input contains several test cases, terminated by EOF. Output For each test case, print the case number at the first line. Then print one line for each query. And remember follow a blank line after each test case.
Sample Input
10 1 2 3 4 5 6 7 8 9 10 5 0 1 10 1 1 10 1 1 5 0 5 8 1 4 8
Sample Output
Case #1: 19 7 6
|
关于这道题的题意先说一下吧,让你去摧毁战舰,1指令是让你汇报地方区间【】的战舰战斗力之和,0指令是让你去降低区间【】范围内敌方战舰的战斗力,每一次降为其原来的sqrt(),我的第一想法就是区间修改,区间求和,上来就噼里啪啦的一顿敲,马上弄完的时候突然意识到,woc!!!平方根好像不满足分配率,也就是说不能像加法减法最值那样进行集体操作,要了老命了,我就只能试试单点操作喽,又是一顿噼里啪啦,给我TLE了,本以为是哪里写错了,瞄了好多眼,愣是找到致命的错误。。。
昨天晚上一共做了两个题,都给TLE了,还都没改出来,难受啊。。。晚上回宿舍的时候听舍友给我说,需要剪枝 ,因为一个int 型的数最多开七八次根号就会很接近1了,这时候无论怎么开根号结果都一样,然后就是疯狂地浪费时间~~~仔细想想好像是这样啊, 那么然后的任务就是找到内部元素sqrt()等于1的区间进行删除,即不用再更新sqrt,直接return 就ojbk,他用的是区间长度等于其区间数值和的思想,舍友tql 日常膜拜 Orz
今天早上吃饭的时候突然灵光一闪,给他个标记不就完了嘛,然后又是万般调试,把所有的坑都遍历的一遍 ~_~ 终于皇天不负有心人,把他给AC了,可能我上辈子就是一棵线段树,太NAN了。。。然鹅心里还没点 B Tree。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int mm=1e5+5;
#define ll long long
struct node{
int l,r;
ll sum;
int flag;//标记sqrt是否为 1
// ll lazy;
}pp[mm<<2];
ll a[mm];
ll res;
void up(int k){
pp[k].sum=pp[k<<1].sum+pp[k<<1|1].sum;
pp[k].flag=pp[k<<1].flag&&pp[k<<1|1].flag;//整个区间的flag为 1才 能合并
}
void build(int k,int l,int r){
pp[k].l=l;
pp[k].r=r;
pp[k].flag=0;
if(l==r){
pp[k].sum=a[l];
if(a[l]<=1)
pp[k].flag=1;//
return ;
}
int mid=(r+l)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
up(k);
}
//void pd(int k){
// if(pp[k].lazy==0)
// return ;
// pp[k<<1].sum=(pp[k<<1].r-pp[k<<1].l+1)*pp[k].lazy;
// pp[k<<1|1].sum=(pp[k<<1|1].r-pp[k<<1|1].l+1)*pp[k].lazy;
// pp[k<<1|1].lazy=pp[k].lazy;
// pp[k<<1].lazy=pp[k].lazy;
// pp[k].lazy=0;
//}
void change(int k,int l,int r){
if(pp[k].flag==1)
return;
//pd(k);
if(pp[k].l==pp[k].r){
pp[k].sum=(ll)sqrt(pp[k].sum*1.0);//注意让平方根四舍五入的方法
if(pp[k].sum<=1)
pp[k].flag=1;//随时更新
return ;
}
int mid=(pp[k].l+pp[k].r)>>1;
// if(r>mid)change(k<<1|1,l,r);
// if(l<=mid)change(k<<1,l,r);
if(mid>=r)change(k<<1,l,r);//
else if(mid<l)change(k<<1|1,l,r);
else {
change(k<<1,l,mid);
change(k<<1|1,mid+1,r);
}
up(k);
}
void query(int k,int l,int r){
if(pp[k].l==l&&pp[k].r==r){
res+=pp[k].sum;
return ;
}
if(pp[k].l==pp[k].r)
return ;
//pd(k);
int mid=(pp[k].l+pp[k].r)>>1;
// if(r>mid)query(k<<1|1,l,r);
// if(l<=mid)query(k<<1,l,r);
if(mid>=r)query(k<<1,l,r);
else if(mid<l)query(k<<1|1,l,r);
else {
query(k<<1,l,mid);
query(k<<1|1,mid+1,r);
}
}
int main()
{
int n,m,test=1;
while(scanf("%d",&n)!=EOF){
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,1,n);
printf("Case #%d:\n",test++);
scanf("%d",&m);
int op,x,y;
while(m--){
scanf("%d%d%d",&op,&x,&y);
if(x>y)swap(x,y);//这是个大坑
if(op==0)change(1,x,y);
else {
res=0;
query(1,x,y);
printf("%lld\n",res);
}
}
printf("\n");
}
return 0;
}