问题摘要:
\(N\)个柱子排成一排,一开始每个柱子损伤度为0。
接下来勇仪会进行\(M\)次攻击,每次攻击可以用4个参数\(l\),\(r\),\(s\),\(e\)来描述:
表示这次攻击作用范围为第\(l\)个到第\(r\)个之间所有的柱子(包含\(l\),\(r\)),对第一个柱子的伤害为\(s\),对最后一个柱子的伤害为\(e\)。
攻击产生的伤害值是一个等差数列。若\(l=1\),\(r=5\),\(s=2\),\(e=10\),则对第1~5个柱子分别产生2,4,6,8,10的伤害。
鬼族们需要的是所有攻击完成之后每个柱子的损伤度。
输入格式
第一行2个整数\(N\),\(M\),用空格隔开,下同。
接下来\(M\)行,每行4个整数\(l\),\(r\),\(s\),\(e\),含义见题目描述。
数据保证对每个柱子产生的每次伤害值都是整数。
输出格式
由于输出数据可能过大无法全部输出,为了确保你真的能维护所有柱子的损伤度,只要输出它们的异或和与最大值即可。
(异或和就是所有数字按位异或起来的值)
(异或运算符在c++里为^)
样例 #1
样例输入 #1
5 2
1 5 2 10
2 4 1 1
样例输出 #1
3 10
样例 #2
样例输入 #2
6 2
1 5 2 10
2 4 1 1
样例输出 #2
3 10
提示
样例解释:
样例1:
第一次攻击产生的伤害:2 4 6 8 10
第二次攻击产生的伤害:0 1 1 1 0
所有攻击结束后每个柱子的损伤程度:2 5 7 9 10。
输出异或和与最大值,就是3 10。
样例2:
没有打到第六根柱子,答案不变
数据范围:
对于全部的数据:\(1\leqslant n\leqslant10^7\),\(1\leqslant m\leqslant3\times 10^5\),\(1\leqslant l<r\leqslant n\).
所有输入输出数据以及柱子受损伤程度始终在\([0,9\times 10^{18}]\)范围内。
等差数列,公差相同。对一个序列的一段加上一个等差数列。
想到差分(我没想到),设 \(a\) 为原数列, \(b\) 为一阶差分数列,\(c\) 为二阶差分数列。
差分是探究数列关系的利器,如果一阶差分不能解决问题,那就再差一阶。另外 多项式也可以差分。
定更改的区间为 \([L,R]\),首项为 \(s\),公差是 \(d\),末项是 \(t = s + (R - L)\times d\)
看对原数列 \(a\) 的影响:\(a_x=a_x + s + (x - L)\times d\)
作一阶差分,看 \(b\) 的影响:\(b_x=a_{x}-a_{x-1}\)
\(b_L = b_L + s\)
\(b_{x}=b_x+d\)
\(b_{R+1}=b_{R+1}-t\)
此时更改次数仍是 \(R-L\) 次,但是已经初见端倪。再看 \(c\) 的变化:\(c_x=b_x-b_{x-1}\)
\(c_L=c_L+s\)
\(c_{L+1}=c_{L+1}+d-s\)
\(c_{x}=c_x\)
\(c_{R+1}=C_{R+1}-t-d\)
\(c_{R+2}=c_{R+2}+t\)
此时找到 \(O(1)\) 算法,每次覆盖只需要改变四个点
#include <bits/stdc++.h>
#define rei register int
#define ll long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define rep(i, s, n, c) for (register int i = s; i <= n; i+=c)
#define repd(i, s, n, c) for (register int i = s; i >= n; i-=c)
#define CHECK cout<<"WALKED"<<endl;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
#define pb push_back
#define ls id<<1
#define rs id<<1|1
const int INF = INT_MAX;
long long binpow(long long a, long long b, ll mod){long long res = 1; while (b > 0){if (b & 1) res = res * a % mod;a = a * a % mod; b >>= 1; } return res;}
using namespace std;
const int maxn = 10000005;
ll a[maxn], b[maxn], c[maxn], maxx, sum;
int n, m;
int l, r, s, e, d;
int main()
{
n = read(); m = read();
for (int i = 1; i <= m; i++) {
l = read(), r = read(), s = read(), e = read();
d = (e - s) / (r - l); // get common difference
// 4 places
c[l] = c[l] + s;
c[l + 1] = c[l + 1] + d - s;
c[r + 1] = c[r + 1] - d - e;
c[r + 2] = c[r + 2] + e;
}
for (int i = 1; i <= n; i++) {
b[i] = b[i - 1] + c[i]; // second diff
a[i] = a[i - 1] + b[i]; // first diff
}
for (int i = 1; i <= n; i++) {
maxx = max(a[i], maxx);
sum ^= a[i];
}
cout << sum << " " << maxx << endl;
return 0;
}
标签:10,柱子,int,样例,必杀,差分,P4231,异或
From: https://www.cnblogs.com/CYLSY/p/16997551.html