题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5828
转载链接:http://blog.csdn.net/xtttgo/article/details/52184771
(数据加强后代码AC)
题意:
线段树基本操作题
给你一个区间 有3个指令
1 l r x:【l,r】+x;
2 l r:【l,r】中的每个元素都得开根号
3 l r : 【l,r】中的值的和
个人感想:
马丹,我今天做了一个上午,才告诉我数据加强了,大部分题解都是T的,然后我也不会了…我只能说说我的想法吧,我现在也没找到一个blog能过的…我这种蒟蒻看不懂大牛的题解…
这题如果有做过区间开根的朋友应该第一想法就是 对于根号的单点更新,直到整段区间是1或者相同的时候合并成单点,然后相当于对区间操作时转化成单点操作.
就算会做,但现在也卡不过了,数据加强了…当时比赛的时候,我也有这个想法,我是感觉会T我都不敢写,然后大部分题解都说合并就可以过了…数据加强后,真的一个都过不了了… 标程也不能过,简直什么鬼…
附加:
现在22:14分,马丹我今天敲了一天了这道题,我终于AC掉了,参考了一下大牛的文章,然后再在自己的基础上改的,转载的大牛文章说有这样的数据 2 3 2 3 2 3…,然后不断的+d,然后再开根,无限的这样子就会必然会T.
然后看了一下大牛文章,当时大牛没修改它原本文章的表达,反正有点奇怪,之后我悟道了什么意思.
这挺神奇的思想,我是没考虑过…
假设某一段区间的最大值x,和最小值y.
如果极差>1,那么这个极差经过很少的次数开根号, 其中的极差也会变得越来越小,
用公式来表达 假设当前这段区间要**+d**,然后再开根号.
必然有这样的式子
##\( \lfloor \sqrt{x+d} \rfloor - \lfloor \sqrt{y+d} \rfloor <= \lfloor \sqrt{x} \rfloor - \lfloor \sqrt{y} \rfloor \)##
就是他的极差会越来越小,反正开一次根号都变得越来越小.
所以我们很容易就求到这个段区间的值.
这里有个小极巧
所以 极差<=1的时候可以特殊处理
假设 这段区间极差==1,那么我们很容易求到这段区间的最大最小值,
因为我们知道上一次的 Sum
所以我们可以这样, 最大值的个数=Sum-(r-l+1)最小值.然后就顺便求出最大值,然后*如果当前区间要开根号的话,**直接就可以求出来了…
好累…回宿舍…
T代码:
/* Author:GavinjouElephant
* Title:
* Number:
* main meanning:
*
*
*
*/
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define lson 2*k
#define rson 2*k+1
typedef long long ll;
const ll INF = 0x3f3f3f3f;
const ll maxn = 1e5 + 10;
ll Scan()//读入整数外挂.
{
ll res = 0, ch, flag = 0;
if((ch = getchar()) == '-') //判断正负
flag = 1;
else if(ch >= '0' && ch <= '9') //得到完整的数
res = ch - '0';
while((ch = getchar()) >= '0' && ch <= '9' )
res = res * 10 + ch - '0';
return flag ? -res : res;
}
void Out(ll a) //输出外挂
{
if(a > 9)
Out(a / 10);
putchar(a % 10 + '0');
//prllf("\n");
}
/*1.加上一个值
2.开根号
3.计算总值
*/
int T;
int n, m;
int op;
int l, r;
ll x;
ll A[maxn];
class Node
{
public:
int l;
int r;
ll sum;
ll lazy;
ll flag;//用flag来判断是否有整段的值都是一样的.
};
Node node[4 * maxn];
void pushup(int k)
{
if(node[lson].flag==node[rson].flag&&node[lson].flag)
{
node[k].flag=node[lson].flag;
}
else node[k].flag=0;
node[k].sum=node[lson].sum+node[rson].sum;
}
void pushdown(int k)
{
if(node[k].flag)
{
node[lson].flag=node[k].flag;
node[rson].flag=node[k].flag;
node[lson].sum=(node[lson].r-node[lson].l+1)*node[k].flag;
node[rson].sum=(node[rson].r-node[rson].l+1)*node[k].flag;
node[k].lazy=0;
}
if(node[k].lazy)
{
node[lson].sum+=(node[lson].r-node[lson].l+1)*node[k].lazy;
node[rson].sum+=(node[rson].r-node[rson].l+1)*node[k].lazy;
if(node[lson].flag)node[lson].flag+=node[k].lazy;
if(node[rson].flag)node[rson].flag+=node[k].lazy;
node[lson].lazy+=node[k].lazy;
node[rson].lazy+=node[k].lazy;
node[k].lazy=0;
}
return;
}
void Build(int l,int r,int k)
{
node[k].l=l;
node[k].r=r;
node[k].lazy=0;
node[k].flag=0;
if(l==r)
{
node[k].flag=node[k].sum=A[l];
return ;
}
int mid=(l+r)/2;
Build(l,mid,lson);
Build(mid+1,r,rson);
pushup(k);
return;
}
void update1(int l, int r, ll v, int k)
{
if(l<=node[k].l&&node[k].r<=r)
{
node[k].lazy+=v;
if(node[k].flag) node[k].flag+=v;
node[k].sum+=(node[k].r-node[k].l+1)*v;
return;
}
int mid=(node[k].l+node[k].r)/2;
pushdown(k);
if(l<=mid)update1(l,min(mid,r),v,lson);
if(r>mid)update1(max(l,mid+1),r,v,rson);
pushup(k);
}
void update2(int l, int r, int k)
{
if(l<=node[k].l&&node[k].r<=r&&node[k].flag)
{
node[k].flag=sqrt(node[k].flag);
node[k].sum=(node[k].r-node[k].l+1)*node[k].flag;
return;
}
int mid=(node[k].l+node[k].r)/2;
pushdown(k);
if(l<=mid)update2(l,min(mid,r),lson);
if(r>mid)update2(max(mid+1,l),r,rson);
pushup(k);
}
ll getsum(int l,int r,int k)
{
ll sum1=0;
ll sum2=0;
if(l<=node[k].l&&node[k].r<=r)
{
return node[k].sum;
}
pushdown(k);
int mid=(node[k].l+node[k].r)/2;
if(l<=mid)sum1=getsum(l,min(mid,r),lson);
if(r>mid)sum2=getsum(max(mid+1,l),r,rson);
return sum1+sum2;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("coco.txt", "r", stdin);
freopen("lala.txt", "w", stdout);
#endif
T=Scan();
while(T--)
{
n=Scan();
m=Scan();
for(int i = 1; i <= n; i++)
{
A[i]=Scan();
}
Build(1,n,1);
while(m--)
{
op=Scan();
l=Scan();
r=Scan();
if(op == 1)
{
x=Scan();
update1(l,r,x,1);
}
else if(op == 2)
{
update2(l,r,1);
}
else if(op == 3)
{
Out(getsum(l,r,1));
puts("");
}
}
}
return 0;
}
AC代码:
/* Author:GavinjouElephant
* Title:
* Number:
* main meanning:
*
*
*
*/
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define lson 2*k
#define rson 2*k+1
typedef long long ll;
const ll INF = 0x3f3f3f3f;
const ll maxn = 1e5 + 10;
ll Scan()//读入整数外挂.
{
ll res = 0, ch, flag = 0;
if((ch = getchar()) == '-') //判断正负
flag = 1;
else if(ch >= '0' && ch <= '9') //得到完整的数
res = ch - '0';
while((ch = getchar()) >= '0' && ch <= '9' )
res = res * 10 + ch - '0';
return flag ? -res : res;
}
void Out(ll a) //输出外挂
{
if(a > 9)
Out(a / 10);
putchar(a % 10 + '0');
//prllf("\n");
}
/*1.加上一个值
2.开根号
3.计算总值
*/
int T;
int n, m;
int op;
int l, r;
ll x;
ll A[maxn];
class Node
{
public:
int l;
int r;
ll sum;
ll b;
ll s;
ll lazy;
ll flag;//用flag来判断是否有整段的值都是一样的.
};
Node node[4 * maxn];
void pushup(int k)
{
if(node[lson].flag == node[rson].flag && node[lson].flag)
{
node[k].flag = node[lson].flag;
}
else node[k].flag = 0;
node[k].sum = node[lson].sum + node[rson].sum;
node[k].b = max(node[lson].b, node[rson].b);
node[k].s = min(node[lson].s, node[rson].s);
}
void pushdown(int k)
{
if(node[k].flag)
{
node[lson].b = node[lson].s = node[lson].flag = node[k].flag;
node[rson].b = node[rson].s = node[rson].flag = node[k].flag;
node[lson].sum = (node[lson].r - node[lson].l + 1) * node[k].flag;
node[rson].sum = (node[rson].r - node[rson].l + 1) * node[k].flag;
node[k].lazy = 0;
}
if(node[k].lazy)
{
node[lson].sum += (node[lson].r - node[lson].l + 1) * node[k].lazy;
node[rson].sum += (node[rson].r - node[rson].l + 1) * node[k].lazy;
if(node[lson].flag)node[lson].flag += node[k].lazy;
if(node[rson].flag)node[rson].flag += node[k].lazy;
node[lson].b += node[k].lazy;
node[lson].s += node[k].lazy;
node[rson].b += node[k].lazy;
node[rson].s += node[k].lazy;
node[lson].lazy += node[k].lazy;
node[rson].lazy += node[k].lazy;
node[k].lazy = 0;
}
return;
}
void Build(int l, int r, int k)
{
node[k].l = l;
node[k].r = r;
node[k].lazy = 0;
node[k].flag = 0;
if(l == r)
{
node[k].b=node[k].s=node[k].flag = node[k].sum = A[l];
return ;
}
int mid = (l + r) / 2;
Build(l, mid, lson);
Build(mid + 1, r, rson);
pushup(k);
return;
}
void update1(int l, int r, ll v, int k)
{
if(l <= node[k].l && node[k].r <= r)
{
node[k].lazy += v;
if(node[k].flag) node[k].flag += v;
node[k].sum += (node[k].r - node[k].l + 1) * v;
node[k].b += v;
node[k].s += v;
return;
}
int mid = (node[k].l + node[k].r) / 2;
pushdown(k);
if(l <= mid)update1(l, min(mid, r), v, lson);
if(r > mid)update1(max(l, mid + 1), r, v, rson);
pushup(k);
}
void update2(int l, int r, int k)
{
if(l <= node[k].l && node[k].r <= r)
{
if(node[k].flag)
{
node[k].flag = sqrt(node[k].flag);
node[k].sum = (node[k].r - node[k].l + 1) * node[k].flag;
node[k].b=node[k].flag;
node[k].s=node[k].flag;
return;
}
else if(node[k].b-node[k].s==1)
{
ll mb=node[k].b;
ll ms=node[k].s;
ll nb=sqrt(mb);
ll ns=sqrt(ms);
node[k].b=nb;
node[k].s=ns;
ll ml=node[k].sum-ms*(node[k].r-node[k].l+1);
ll nl=(node[k].r-node[k].l+1)-ml;
if( (nb-ns) == 1)
{
node[k].lazy+=(nb-mb);
node[k].sum=nb*ml+ns*nl;
}
else
{
node[k].lazy=0;
node[k].flag=nb;
node[k].sum=(node[k].r-node[k].l+1)*nb;
}
return ;
}
}
pushdown(k);
int mid = (node[k].l + node[k].r) / 2;
if(l <= mid)update2(l, min(mid, r), lson);
if(r > mid)update2(max(mid + 1, l), r, rson);
pushup(k);
}
ll getsum(int l, int r, int k)
{
ll sum1 = 0;
ll sum2 = 0;
if(l <= node[k].l && node[k].r <= r)
{
return node[k].sum;
}
pushdown(k);
int mid = (node[k].l + node[k].r) / 2;
if(l <= mid)sum1 = getsum(l, min(mid, r), lson);
if(r > mid)sum2 = getsum(max(mid + 1, l), r, rson);
return sum1 + sum2;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("coco.txt", "r", stdin);
freopen("lala.txt", "w", stdout);
#endif
T = Scan();
while(T--)
{
n = Scan();
m = Scan();
for(int i = 1; i <= n; i++)
{
A[i] = Scan();
}
Build(1, n, 1);
while(m--)
{
op = Scan();
l = Scan();
r = Scan();
if(op == 1)
{
x = Scan();
update1(l, r, x, 1);
}
else if(op == 2)
{
update2(l, r, 1);
}
else if(op == 3)
{
Out(getsum(l, r, 1));
printf("\n");
}
}
}
return 0;
}