膜一下zkw神犇 另外fread真的快。。
题目:
http://www.lydsy.com/JudgeOnline/problem.php?id=4373
大意:给你一个n的数列,每次查询一段区间[l,r]内的数字排序后是否构成公差为k的等差数列。并且有修改操作。
思路:难点就在于判断是否构成等差数列。我们可以用平方和的方式,Hash一下,然后和等差数列平方和公式算出来的值进行比对,如果不一致那么说明其中有数不一样,即不构成等差数列。然后就是线段树一通乱搞(确信
这个是我看下来觉得写的最明白的zkw线段树的介绍(教程)。当然了也可以去看zkw本尊的ppt《统计的力量》。
#include<iostream>
#include<string>
#include<cstring>
#include<stdlib.h>
#include<cstdio>
#include<stdio.h>
#include<set>
#include<map>
#include<deque>
#include<stack>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<list>
#include<fstream>
#include <bitset>
using namespace std;
typedef long long ll;
const int maxn = 300010;
const int INF = 0x3f3f3f3f;
int bas = 1;
struct seg {
int mn;ll sum2;
}t[maxn << 2];
char * cp=(char *)malloc(20000000);
void in(int &x){
while(*cp<'0'||*cp>'9')++cp;
for(x=0;*cp>='0'&&*cp<='9';)x=x*10+(*cp++^'0');
}
inline void pushup(int n)
{
t[n].mn = min(t[n << 1].mn, t[n << 1 | 1].mn);
t[n].sum2 = t[n << 1].sum2 + t[n << 1 | 1].sum2;
}
void build(int n)
{
while (bas < (n + 2))//底层有几个节点
bas <<= 1;
for (int i = bas + 1;i <= bas + n;i++)
{
in(t[i].mn);t[i].sum2 = t[i].mn *t[i].mn * 6;//这里让平方和乘以6因为公式里有除以6,为了避免除法和逆元什么的乱七八糟的东西
}
for (int i = bas - 1;i > 0;i--)
pushup(i);
}
void update(int n, int val)
{
n += bas;
t[n].mn = t[n].sum2 = val;
t[n].sum2 = t[n].sum2 * t[n].sum2 * 6;
for (n >>= 1;n > 0;n >>= 1) //一直更新到根节点
pushup(n);
}
ll qsum(int l, int r)
{
ll ans = 0;
for (l += bas - 1, r += bas + 1;l^r ^ 1;l >>= 1, r >>= 1)
{
if ((~l) & 1)ans = ans + t[l ^ 1].sum2; //如果左边的节点是左儿子则把右儿子加入sum
if (r & 1)ans =ans + t[r ^ 1].sum2; //如果右边的节点是右儿子则把左儿子加入sum
}
return ans;
}
int qmin(int l, int r)
{
int ans = INF;
for (l += bas - 1, r += bas + 1;l^r ^ 1;l >>= 1, r >>= 1)
{
if ((~l) & 1)ans = min(ans, t[l ^ 1].mn);
if (r & 1)ans = min(ans, t[r ^ 1].mn);
}
return ans;
}
int main()
{
int n, m, opt, l, r, k, cnt = 0;
fread(cp,1,20000000,stdin);
in(n);in(m);
build(n);
while (m--)
{
in(opt);in(l);in(r);
l ^= cnt, r ^= cnt;
if (opt == 2)
{
in(k);
k ^= cnt;
int sum = qsum(l, r), mm = qmin(l, r), len = r- l;
if (sum == mm*mm*(len + 1) * 6 + len*(len + 1)*mm*k * 6 + len*(len + 1)*(len << 1 | 1)*k*k)
{
cnt++;printf("Yes\n");
}
else printf("No\n");
}
else if (opt == 1)
{
update(l, r);
}
}
return 0;
}