NKOJ 2997 狗 【nodgd造水题】
时间限制 : 6000 MS 空间限制 : 131072 KB
问题描述
nodgd家里有很多狗!太多的狗给nodgd带来了各种麻烦,于是nodgd决定开个赶走一些狗!
nodgd首先按照狗的品种把所有狗分成N类,依次是第1类,第2类,…,第N类。刚开始第i类有ai只。
nodgd有时候会心情不爽,就会把第l类、第l+1类、第l+2类、…、第r-1类、第r类的每类狗都进行这样的操作:
第一步,把这类狗排成一个尽量大的正方形方阵,多余的狗就赶走!
第二步,在正方形方阵中每一横排任选一条狗留下,其余全部赶走!
当然,狗也是需要喂食的,喂食之前需要先知道有多少条狗。因为赶走了一些狗,所以nodgd也记不清楚到底有多少条狗了,他可能会问你,第l类、第l+1类、第l+2类、…、第r-1类、第r类一共还剩多少条狗?你作为一个优秀的程序员,当然可以写个程序来回答nodgd的提问啦!
简化版题目描述:给个序列,区间开方,向下取整,区间求和。
输入格式
第一行两个整数N,M,分别表示狗的种类数和操作次数
第二行N个整数a1,a2,…,aN,表示每类狗一开始有多少条
接下来M行,每行三个整数k,l,r。若k=0则表示nodgd心情不爽了又要赶走一些狗了,若k=1则表示nodgd打算给狗喂食了就先向你提问
输出格式
对于nodgd的每次提问输出答案
样例输入
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
样例输出
19
7
6
提示
样例解释:
第一次操作之后狗的数量分别是1,1,1,2,2,2,2,2,3,3.
第四次操作之后狗的数量分别是1,1,1,2,1,1,1,1,3,3.
数据范围:
1<=N<=100000
1<=M<=100000
1<=ai<=1012
1<=l<=r<=N
来源 感谢nodgd抄袭别人的题目并提供数据
思路:
每次修改虽然是区间,但是每次一定要修改到叶节点,所以用不用lazy都差不多…..
结论:lazy使用条件:不知道子树信息也可以更新
注意开方很容易开成1,用1来“剪枝”。
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
#define ll long long
const int need=100003;
struct fy{ll val;int a,b;}t[need<<1];
int le[need<<1],ri[need<<1],tot=0;
ll a[need];
ll x,y;
inline void in_(ll &d)
{
bool mark=false;char t=getchar();
while(t<'0'||t>'9'){if(t=='-') mark=true;t=getchar();}
for(d=0;t>='0'&&t<='9';t=getchar())d=(d<<3)+(d<<1)-'0'+t;
if(mark)d=-d;
}
char o[100];
inline void out_(ll x)
{
int l=1;
if(x<0) x=-x,putchar('-');
if(!x) putchar('0');
for(;x;x/=10) o[l++]=x%10+'0';
for(l--;l;l--)putchar(o[l]);
putchar('\n');
}
void build(int x,int y)
{
int s=++tot;
t[s].a=x,t[s].b=y;
if(x==y)
{
t[s].val=a[x];
return ;
}
le[s]=tot+1;build(x,(x+y)>>1);
ri[s]=tot+1;build((x+y)/2+1,y);
t[s].val=t[le[s]].val+t[ri[s]].val;
}
void modify(int s)
{
if(t[s].val==t[s].b-t[s].a+1) return ;//表示该区间所有狗都为1,修改后无变化。
if(t[s].a>y||t[s].b<x) return ;
if(t[s].a==t[s].b)
{
t[s].val=t[s].val==1?1:floor(sqrt(t[s].val));
return ;
}
modify(le[s]),modify(ri[s]);
t[s].val=t[le[s]].val+t[ri[s]].val;
}
ll getans(int s)
{
if(t[s].a>y||t[s].b<x) return 0;
if(x<=t[s].a&&t[s].b<=y) return t[s].val;
return getans(le[s])+getans(ri[s]);
}
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)
in_(a[i]);//scanf("%I64d",a[i]);
build(1,n);
int m;scanf("%d",&m);
ll aa;
for(int i=1;i<=m;i++)
{
in_(aa),in_(x),in_(y);//scanf("%d%d%d",&a,&x,&y);
if(aa==0) modify(1);
else out_(getans(1));//printf("%I64d",getans(1));
}
}