目录:
OP
感谢学长的讲解与付出;
感谢ph和zsl两位大佬的指导与讨论;
夹带私货:
此节课的代表性的内容已经整理到自己的贴子中:【笔记】数据结构
线段树本身相对抽象,一些题又有懒标记的要求,实在不太好理解;
从应用来讲,线段树可以快速地进行区间修改与区间查询,但是所需空间复杂度比较大,有时需要离散化处理;
A Lowbit
思路
朴素来讲,我们会在进行区间更改时递归到所有叶节点进行lowbit更改,但是这种做法会被卡T;
我们可以发现,若某叶节点元素 a 满足
l
o
w
b
i
t
(
a
)
=
a
lowbit(a)=a
lowbit(a)=a,则
a
+
l
o
w
b
i
t
(
a
)
=
2
a
a+lowbit(a)=2a
a+lowbit(a)=2a,并且
l
o
w
b
i
t
(
a
)
=
a
lowbit(a)=a
lowbit(a)=a的性质不会改变;
除此之外,若某节点 s 下所有叶节点元素 a 均满足
l
o
w
b
i
t
(
a
)
=
a
lowbit(a)=a
lowbit(a)=a,则对 s 区间进行操作后,等价与
2
s
2s
2s,并且
l
o
w
b
i
t
(
a
)
=
a
lowbit(a)=a
lowbit(a)=a的性质也不会改变;
我们可以用此性质,懒标记存储此节点有多少次二倍操作未下传,就可以一定程度上降低时间复杂度;
代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e5;
const int M = 998244353;
struct
{
int l, r, is; //l,r为节点的左右界
ll sum, lt; //sum为节点值,lt为懒标记
} segt[N << 2 | 1];
ll qm(ll a,ll b)//qm即quick_mod
{
ll ans=1%M;//特殊处理M=1这一特殊情况
for(;b;b>>=1)
{
if(b&1)ans=a*ans%M;//如果b此位为1
a=a*a%M;
}
return ans;
}
ll lowbit(ll x) { return x & -x; }
bool check(ll x) { return !(x - lowbit(x)); }
void pushdown(int p) //对懒标记进行下传
{
if (segt[p].lt)
{
segt[p << 1].sum=segt[p << 1].sum*qm(2,segt[p].lt)%M;
segt[p << 1|1].sum=segt[p << 1|1].sum*qm(2,segt[p].lt)%M;
segt[p << 1].lt+=segt[p].lt;
segt[p << 1|1].lt+=segt[p].lt;
segt[p].lt = 0;
}
return;
}
void build(int p, int cl, int cr)
{
segt[p].l = cl, segt[p].r = cr, segt[p].lt = 0, segt[p].sum = 0, segt[p].is = 0;
if (cl == cr)
{
scanf("%lld", &segt[p].sum);
segt[p].is = check(segt[p].sum);
return;
}
int mid = cl + cr >> 1;
build(p << 1, cl, mid);
build(p << 1 | 1, mid + 1, cr);
segt[p].sum = segt[p << 1].sum + segt[p << 1 | 1].sum;
segt[p].is = segt[p<<1].is&&segt[p<<1|1].is;
if (segt[p].is)
segt[p].sum %= M;
}
void icg(int p, int cl, int cr)
{
if (cl <= segt[p].l && segt[p].r <= cr && segt[p].is)
{
segt[p].sum <<= 1;
segt[p].lt++;
segt[p].sum %= M;
return;
}
if (segt[p].l == segt[p].r)
{
segt[p].sum += lowbit(segt[p].sum);
segt[p].is = check(segt[p].sum);
if (segt[p].is)
segt[p].sum %= M;
return;
}
pushdown(p);
int mid = segt[p].r + segt[p].l >> 1;
if (cl <= mid)
icg(p << 1, cl, cr);
if (cr >= mid + 1)
icg(p << 1 | 1, cl, cr);
segt[p].sum = segt[p << 1].sum + segt[p << 1 | 1].sum;
segt[p].is = segt[p<<1].is&&segt[p<<1|1].is;
segt[p].sum %= M;
}
ll ick(int p, int cl, int cr)
{
if (cl <= segt[p].l && segt[p].r <= cr)
return segt[p].sum;
pushdown(p);
int mid = segt[p].r + segt[p].l >> 1;
ll val = 0;
if (cl <= mid)
val += ick(p << 1, cl, cr), val %= M;
if (cr >= mid + 1)
val += ick(p << 1 | 1, cl, cr), val %= M;
return val;
}
int main()
{
int n, t, q, l, r, o;
cin >> t;
while (t--)
{
scanf("%d", &n);
build(1, 1, n);
scanf("%d", &q);
for (int i = 1; i <= n; i++)
{
scanf("%d%d%d", &o, &l, &r);
if (o == 1)
{
icg(1, l, r);
}
else if (o == 2)
{
printf("%lld\n", ick(1, l, r));
}
}
}
}
B Ezzat and Grid
参考
线段树+dp
思路
首先左右界的数据范围过大,需要离散化处理;
定义dp函数
d
p
[
i
]
dp[i]
dp[i]为以第i行为末尾的最长可行序列长度,在线段树内存储结点下前i-1行该节点内的
d
p
[
i
]
dp[i]
dp[i]最大值;
对于某一行的若干的区间,假设有区间内的可行序列长度最大值为a,则有
d
p
[
i
]
=
a
+
1
dp[i]=a+1
dp[i]=a+1;
同时持续更新答案的最大值(即
d
p
[
i
]
dp[i]
dp[i])即可;
但是此题要求输出应被删掉的点,就需要在维护线段树时同时记录该最大值对应的行号,在进行
d
p
[
i
]
dp[i]
dp[i]的修改时同时标记
f
a
[
i
]
fa[i]
fa[i]即可;
再通过上溯找到没有在这个序列中的点即可;
代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 6e5;
const int M = 998244353;
struct
{
int l, r; //l,r为节点的左右界
ll lt; //sum为节点值,lt为懒标记
pair<ll, int> sum;
} segt[N << 2 | 1];
map<int, int> mp;
int c = 0, ch = 1, gh[600005];
int dp[300005], fa[300005];
void pushdown(int p) //对懒标记进行下传
{
if (segt[p].lt)
{
segt[p << 1].sum = segt[p].sum;
segt[p << 1 | 1].sum = segt[p].sum;
segt[p << 1].lt = segt[p << 1 | 1].lt = 1;
segt[p].lt = 0;
}
return;
}
void build(int p, int cl, int cr)
{
segt[p].l = cl, segt[p].r = cr, segt[p].lt = 0, segt[p].sum = {0, 0};
if (cl == cr)
{
//scanf("%lld", &segt[p].sum);
return;
}
int mid = cl + cr >> 1;
build(p << 1, cl, mid);
build(p << 1 | 1, mid + 1, cr);
segt[p].sum = max(segt[p << 1].sum, segt[p << 1 | 1].sum);
}
void icg(int p, int cl, int cr, pair<ll, int> d)
{
if (cl <= segt[p].l && segt[p].r <= cr)
{
if (d >= segt[p].sum)
segt[p].sum = d, segt[p].lt = 1;
return;
}
pushdown(p);
int mid = segt[p].r + segt[p].l >> 1;
if (cl <= mid)
icg(p << 1, cl, cr, d);
if (cr >= mid + 1)
icg(p << 1 | 1, cl, cr, d);
segt[p].sum = max(segt[p << 1].sum, segt[p << 1 | 1].sum);
}
pair<ll, int> ick(int p, int cl, int cr)
{
if (cl <= segt[p].l && segt[p].r <= cr)
return segt[p].sum;
pushdown(p);
int mid = segt[p].r + segt[p].l >> 1;
pair<ll, int> val = {0, 0};
if (cl <= mid)
val = max(val, ick(p << 1, cl, cr));
if (cr >= mid + 1)
val = max(val, ick(p << 1 | 1, cl, cr));
return val;
}
pair<int, pair<int, int>> opt;
vector<pair<int, int>> iq[300005];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d", &opt.first, &opt.second.first, &opt.second.second);
gh[c++] = opt.second.first;
gh[c++] = opt.second.second;
iq[opt.first].push_back(opt.second);
}
sort(gh, gh + c);
mp[gh[0]] = ch++;
for (int i = 1; i < c; i++)
{
if (gh[i] == gh[i - 1])
continue;
mp[gh[i]] = ch++;
}
build(1, 1, ch);
int ans = 0, tail = 0;
for (int i = 1; i <= n; i++)
{
pair<ll, int> mx = {0, 0};
for (int j = 0; j < iq[i].size(); j++)
{
pair<ll, int> g = ick(1, mp[iq[i][j].first], mp[iq[i][j].second]);
if (g > mx)
mx = g;
}
dp[i] = mx.first + 1;
fa[i] = mx.second;
if (dp[i] > ans)
{
ans = dp[i];
tail = i;
}
for (int j = 0; j < iq[i].size(); j++)
{
icg(1, mp[iq[i][j].first], mp[iq[i][j].second], {dp[i], i});
}
}
printf("%d", n - ans);
if (ans != n)
{
printf("\n");
int now = tail, p = n;
while (p != now)
{
printf("%d ", p--);
}
while (1)
{
p--;
now = fa[now];
while (p != now)
{
printf("%d ", p--);
}
if(!now)break;
}
}
}
C 奇数国
思路
朴素来讲,我们可以在维护乘积线段树的同时,用一个桶数组维护结点的乘积值内有什么质数,有 s t [ p ] . p r i [ i ] = s t [ p < < 1 ] . p r i [ i ] ∣ s t [ p < < 1 ∣ 1 ] . p r i [ i ] st[p].pri[i]=st[p<<1].pri[i]\ |\ st[p<<1|1].pri[i] st[p].pri[i]=st[p<<1].pri[i] ∣ st[p<<1∣1].pri[i];
但是如此存储的话,时间即为 60 n ⋅ log n 60n\cdotp \log n 60n⋅logn,约为 7 e 7 7e7 7e7,比较悬;
但是仔细观察,60个质数的存在性不必用数组维护,还可以用long long内的数位维护,用 [ ( s t [ p ] . p r i > > i ) & 1 ] [(st[p].pri>>i)\&1] [(st[p].pri>>i)&1]表示p结点下是否有质数 p i p_i pi,更新时变成了 s t [ p ] . p r i = s t [ p < < 1 ] . p r i ∣ s t [ p < < 1 ∣ 1 ] . p r i st[p].pri=st[p<<1].pri\ |\ st[p<<1|1].pri st[p].pri=st[p<<1].pri ∣ st[p<<1∣1].pri,时间复杂度降低啦;
最后结合快速幂和逆元进行欧拉函数值的求取即可;
代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <map>
#include <vector>
typedef long long ll;
using namespace std;
const ll M = 19961993;
const int N = 1e5;
struct
{
int l, r; //l,r为节点的左右界
ll sum, ppos; //sum为节点值
} segt[N << 2 | 1];
int pri[62] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281};
ll qm(ll a, ll b)
{
ll ans = 1;
for (; b; b >>= 1)
{
if (b & 1)
ans = ans * a % M;
a = a * a % M;
}
return ans;
}
void build(int p, int cl, int cr)
{
segt[p].l = cl, segt[p].r = cr, segt[p].ppos = 2, segt[p].sum = 0;
if (cl == cr)
{
segt[p].sum = 3;
return;
}
int mid = cl + cr >> 1;
build(p << 1, cl, mid);
build(p << 1 | 1, mid + 1, cr);
segt[p].sum = (segt[p << 1].sum * segt[p << 1 | 1].sum) % M;
}
void pcg(int p, int x, ll v, ll pnow)
{
if (segt[p].l == segt[p].r)
{
segt[p].sum = v;
segt[p].ppos = pnow;
return;
}
int mid = segt[p].l + segt[p].r >> 1;
if (x <= mid)
pcg(p << 1, x, v, pnow);
else
pcg(p << 1 | 1, x, v, pnow);
segt[p].sum = (segt[p << 1].sum * segt[p << 1 | 1].sum) % M;
segt[p].ppos = segt[p << 1].ppos | segt[p << 1 | 1].ppos;
}
pair<ll, ll> ick(int p, int cl, int cr)
{
if (cl <= segt[p].l && segt[p].r <= cr)
return {segt[p].sum, segt[p].ppos};
int mid = segt[p].r + segt[p].l >> 1;
pair<ll, ll> val = {1, 0}, tmp = {0, 0};
if (cl <= mid)
{
tmp = ick(p << 1, cl, cr);
val.first = val.first*tmp.first%M;
val.second |= tmp.second;
}
if (cr >= mid + 1)
{
tmp = ick(p << 1 | 1, cl, cr);
val.first = val.first*tmp.first%M;
val.second |= tmp.second;
}
val.first%=M;
return val;
}
int main()
{
int n = 100000, m;
ll a, b, c;
scanf("%d", &m);
build(1,1,n);
while (m--)
{
scanf("%lld%lld%lld",&a,&b,&c);
if(!a)
{
pair<ll, ll>tmp=ick(1,b,c);
ll ans=tmp.first;
for(int i=0;i<60;i++)
{
if((tmp.second>>i)&1ll)
{
ans=(ans-(ans*qm(pri[i],M-2))%M+M)%M;
}
}
printf("%lld\n",ans);
}
else
{
ll pnow=0;
for(int i=0;i<60;i++)
{
if(c%pri[i]==0)pnow|=(1ll<<i);
}
pcg(1,b,c,pnow);
}
}
return 0;
}
D 敌兵布阵
思路
板~
单点修改,区间查询
代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N = 1e5 + 5;
struct
{
int l, r;//l,r为节点的左右界
ll sum, lt;//sum为节点值,lt为懒标记
} segt[N << 2];
void build(int p, int cl, int cr)
{
segt[p].l = cl, segt[p].r = cr, segt[p].lt = 0, segt[p].sum = 0;
if (cl == cr)
{
scanf("%lld",&segt[p].sum);
return;
}
int mid = cl + cr >> 1;
build(p << 1, cl, mid);
build(p << 1 | 1, mid + 1, cr);
segt[p].sum = segt[p << 1].sum + segt[p << 1 | 1].sum;
}
void pcg(int p, int x, ll v)//不兼容懒标记
{
if (segt[p].l == segt[p].r)
{
segt[p].sum += v;
return;
}
int mid = segt[p].l + segt[p].r >> 1;
if (x <= mid)
pcg(p << 1, x, v);
else
pcg(p << 1 | 1, x, v);
segt[p].sum = segt[p << 1].sum + segt[p << 1 | 1].sum;
}
ll ick(int p, int cl, int cr)
{
if (cl <= segt[p].l && segt[p].r <= cr)
return segt[p].sum;
int mid = segt[p].r + segt[p].l >> 1;
ll val = 0;
if (cl <= mid)
val += ick(p << 1, cl, cr);
if (cr >= mid + 1)
val += ick(p << 1 | 1, cl, cr);
return val;
}
int main()
{
int t,n,a,b,c=1;
cin>>t;
while(t--)
{
printf("Case %d:\n",c++);
scanf("%d",&n);
build(1,1,n);
string o;
while(cin>>o&&o!="End")
{
scanf("%d%d",&a,&b);
if(o=="Query")
{
printf("%lld\n",ick(1,a,b));
}
else if(o=="Add")
{
pcg(1,a,b);
}
else if(o=="Sub")
{
pcg(1,a,-b);
}
}
}
}
E I Hate It
思路
板~
单点修改,区间查询
代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N = 2e5;
struct
{
int l, r;//l,r为节点的左右界
ll sum, lt;//sum为节点值,lt为懒标记
} segt[N << 2|1];
void build(int p, int cl, int cr)
{
segt[p].l = cl, segt[p].r = cr, segt[p].lt = 0, segt[p].sum = 0;
if (cl == cr)
{
scanf("%lld",&segt[p].sum);
return;
}
int mid = cl + cr >> 1;
build(p << 1, cl, mid);
build(p << 1 | 1, mid + 1, cr);
segt[p].sum = max(segt[p << 1].sum , segt[p << 1 | 1].sum);
}
void pcg(int p, int x, ll v)//不兼容懒标记
{
if (segt[p].l == segt[p].r)
{
segt[p].sum = v;
return;
}
int mid = segt[p].l + segt[p].r >> 1;
if (x <= mid)
pcg(p << 1, x, v);
else
pcg(p << 1 | 1, x, v);
segt[p].sum =max(segt[p << 1].sum , segt[p << 1 | 1].sum);
}
ll ick(int p, int cl, int cr)
{
if (cl <= segt[p].l && segt[p].r <= cr)
return segt[p].sum;
int mid = segt[p].r + segt[p].l >> 1;
ll val = 0;
if (cl <= mid)
val=max(val, ick(p << 1, cl, cr));
if (cr >= mid + 1)
val=max(val, ick(p << 1 | 1, cl, cr));
return val;
}
int main()
{
int m,n,a,b;
while(~scanf("%d%d",&n,&m))
{
build(1,1,n);
char o;
while(m--)
{
cin>>o;
scanf("%d%d",&a,&b);
if(o=='Q')
{
printf("%lld\n",ick(1,a,b));
}
else if(o=='U')
{
pcg(1,a,b);
}
}
}
}
F Transformation
思路
p ∈ { 1 , 2 , 3 } p\in\{1,2,3\} p∈{1,2,3}朴素来讲,我们可以使用三个懒标记和三个值维护未下传的区间加(ad),区间乘(mu),区间更改(cg)操作和区间下的元素和(sum1),元素平方和(sum2),区间立方和(sum3);
但是我们就面临一个问题,如果某位同时存在多种标记,如何判断它们的先后顺序?
在查阅资料时发现,有人在更新时选择先把当前结点的其他标记下传,但是被卡t了;
我们可以制定以下策略:
- 对某结点进行cg操作时,直接修改三个sum值,清空ad和mu标记;
- 对某结点进行mu操作时(假设区间乘d),维护三个sum值,对现有的ad标记乘d,mu标记也乘d;
- 对某节点进行ad操作时(假设区间加d),通过 完全平方公式 和 完全立方公式 维护三个num值,对现有ad标记加d;
以此策略进行维护后,在下传懒标记时只需要以cg,mu,ad的顺序修改子节点就可以规避顺序问题;
代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <map>
#include <vector>
typedef long long ll;
using namespace std;
const int M = 10007;
const int N = 1e5;
struct
{
int l, r; //l,r为节点的左右界
ll sum1, sum2, sum3, ad, mu, cg; //sum为节点值
} segt[N << 2 | 1];
void cgcg(int p, ll d)
{
segt[p].sum1 = d * (segt[p].r - segt[p].l + 1) % M;
segt[p].sum2 = d * d * (segt[p].r - segt[p].l + 1) % M;
segt[p].sum3 = d * d * d * (segt[p].r - segt[p].l + 1) % M;
segt[p].cg = d;
segt[p].ad = 0;
segt[p].mu = 1;
}
void cgmu(int p, ll d)
{
segt[p].sum1 = segt[p].sum1 * d % M;
segt[p].sum2 = segt[p].sum2 * d * d % M;
segt[p].sum3 = segt[p].sum3 * d * d * d % M;
segt[p].ad = segt[p].ad * d % M;
segt[p].mu = segt[p].mu * d % M;
}
void cgad(int p, ll d)
{
int lenp = segt[p].r - segt[p].l + 1;
segt[p].sum3 = (segt[p].sum3 + lenp * d * d * d + 3 * segt[p].sum1 * d * d + 3 * segt[p].sum2 * d) % M;
segt[p].sum2 = (segt[p].sum2 + lenp * d * d + 2 * segt[p].sum1 * d) % M;
segt[p].sum1 = (segt[p].sum1 + lenp * d) % M;
segt[p].ad = (segt[p].ad + d) % M;
}
void pushdown(int p) //对懒标记进行下传
{
if (segt[p].cg)
{
cgcg(p << 1, segt[p].cg);
cgcg(p << 1 | 1, segt[p].cg);
segt[p].cg = 0;
}
if (segt[p].mu != 1)
{
cgmu(p << 1, segt[p].mu);
cgmu(p << 1 | 1, segt[p].mu);
segt[p].mu = 1;
}
if (segt[p].ad)
{
cgad(p << 1, segt[p].ad);
cgad(p << 1 | 1, segt[p].ad);
segt[p].ad = 0;
}
}
void build(int p, int cl, int cr)
{
segt[p].l = cl, segt[p].r = cr;
segt[p].sum1 = 0, segt[p].sum2 = 0, segt[p].sum3 = 0;
segt[p].ad = 0, segt[p].mu = 1, segt[p].cg = 0;
if (cl == cr)
{
//scanf("%lld", &segt[p].sum);
return;
}
int mid = cl + cr >> 1;
build(p << 1, cl, mid);
build(p << 1 | 1, mid + 1, cr);
}
void icg(int p, int cl, int cr, int o, ll d)
{
if (cl <= segt[p].l && segt[p].r <= cr)
{
if (o == 1)
{
cgad(p, d);
}
else if (o == 2)
{
cgmu(p, d);
}
else if (o == 3)
{
cgcg(p, d);
}
return;
}
pushdown(p);
int mid = segt[p].r + segt[p].l >> 1;
if (cl <= mid)
icg(p << 1, cl, cr, o, d);
if (cr >= mid + 1)
icg(p << 1 | 1, cl, cr, o, d);
segt[p].sum1 = (segt[p << 1].sum1 + segt[p << 1 | 1].sum1) % M;
segt[p].sum2 = (segt[p << 1].sum2 + segt[p << 1 | 1].sum2) % M;
segt[p].sum3 = (segt[p << 1].sum3 + segt[p << 1 | 1].sum3) % M;
}
ll ick(int p, int cl, int cr, int k)
{
if (cl <= segt[p].l && segt[p].r <= cr)
{
if (k == 1)
return segt[p].sum1;
else if (k == 2)
return segt[p].sum2;
else if (k == 3)
return segt[p].sum3;
}
pushdown(p);
int mid = segt[p].r + segt[p].l >> 1;
ll val = 0;
if (cl <= mid)
val += ick(p << 1, cl, cr, k);
if (cr >= mid + 1)
val += ick(p << 1 | 1, cl, cr, k);
return val % M;
}
int main()
{
int n, m, x, y, d, o;
while (~scanf("%d%d", &n, &m) && (n || m))
{
build(1, 1, n);
while (m--)
{
scanf("%d%d%d%d", &o, &x, &y, &d);
if(o!=4)
{
icg(1,x,y,o,d);
}
else
{
printf("%lld\n",ick(1,x,y,d));
}
}
}
return 0;
}
G Can you answer these queries?
思路
朴素地想,对于一次修改,递归到叶节点进行平方根操作,很不幸,会卡时间;
但是我们可以发现,如果某叶节点的值若为1或0,则进行平方根修改并不能影响其的值;
这样就可以进行标记,如果某节点下所有点都是1或0,则不需要对其进行修改,降低了复杂度;
这道题很坑的一点是,区间左右界的相对大小并不明确,需要修正非法数据;
代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 5;
struct
{
int l, r; //l,r为节点的左右界
ll sum, lt; //sum为节点值,lt为懒标记
} segt[N << 2];
void build(int p, int cl, int cr)
{
segt[p].l = cl, segt[p].r = cr, segt[p].lt = 0, segt[p].sum = 0;
if (cl == cr)
{
scanf("%lld", &segt[p].sum);
segt[p].lt = segt[p].sum <= 1;
return;
}
int mid = cl + cr >> 1;
build(p << 1, cl, mid);
build(p << 1 | 1, mid + 1, cr);
segt[p].sum = segt[p << 1].sum + segt[p << 1 | 1].sum;
segt[p].lt = (segt[p << 1].lt == 1 && segt[p << 1 | 1].lt == 1);
}
void icg(int p, int cl, int cr)
{
if (segt[p].lt)
return;
if (segt[p].l == segt[p].r)
{
segt[p].sum = (ll)sqrt(segt[p].sum*1.0);
segt[p].lt = segt[p].sum <= 1;
return;
}
int mid = segt[p].r + segt[p].l >> 1;
if (cl <= mid)
icg(p << 1, cl, cr);
if (cr >= mid + 1)
icg(p << 1 | 1, cl, cr);
segt[p].sum = segt[p << 1].sum + segt[p << 1 | 1].sum;
segt[p].lt = (segt[p << 1].lt == 1 && segt[p << 1 | 1].lt == 1);
}
ll ick(int p, int cl, int cr)
{
if (cl <= segt[p].l && segt[p].r <= cr)
return segt[p].sum;
int mid = segt[p].r + segt[p].l >> 1;
ll val = 0;
if (cl <= mid)
val += ick(p << 1, cl, cr);
if (cr >= mid + 1)
val += ick(p << 1 | 1, cl, cr);
return val;
}
int main()
{
int n, q, l, r, k, c = 1;
while (~scanf("%d", &n))
{
printf("Case #%d:\n", c++);
build(1, 1, n);
scanf("%d", &q);
for (int i = 1; i <= q; i++)
{
scanf("%d%d%d", &k, &l, &r);
if(l>r)swap(l,r);
if (k == 0)
icg(1, l, r);
else if (k == 1)
printf("%lld\n", ick(1, l, r));
}
printf("\n");
}
}
H A Simple Problem with Integers
思路
板~
区间修改,区间查询;
代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e5;
struct
{
int l, r;//l,r为节点的左右界
ll sum, lt;//sum为节点值,lt为懒标记
} segt[N << 2 | 1];
void pushdown(int p)//对懒标记进行下传
{
if (segt[p].lt)
{
segt[p << 1].sum += segt[p].lt * (segt[p << 1].r - segt[p << 1].l + 1);
segt[p << 1 | 1].sum += segt[p].lt * (segt[p << 1 | 1].r - segt[p << 1 | 1].l + 1);
segt[p << 1].lt += segt[p].lt;
segt[p << 1 | 1].lt += segt[p].lt;
segt[p].lt = 0;
}
}
void build(int p, int cl, int cr)
{
segt[p].l = cl, segt[p].r = cr, segt[p].lt = 0, segt[p].sum = 0;
if (cl == cr)
{
scanf("%lld", &segt[p].sum);
return;
}
int mid = cl + cr >> 1;
build(p << 1, cl, mid);
build(p << 1 | 1, mid + 1, cr);
segt[p].sum = segt[p << 1].sum + segt[p << 1 | 1].sum;
}
void icg(int p, int cl, int cr, ll d)
{
if (cl <= segt[p].l && segt[p].r <= cr)
{
segt[p].sum += d * (segt[p].r - segt[p].l + 1);
segt[p].lt += d;
return;
}
pushdown(p);
int mid = segt[p].r + segt[p].l >> 1;
if (cl <= mid)
icg(p << 1, cl, cr, d);
if (cr >= mid + 1)
icg(p << 1 | 1, cl, cr, d);
segt[p].sum = segt[p << 1].sum + segt[p << 1 | 1].sum;
}
ll ick(int p, int cl, int cr)
{
if (cl <= segt[p].l && segt[p].r <= cr)
return segt[p].sum;
pushdown(p);
int mid = segt[p].r + segt[p].l >> 1;
ll val = 0;
if (cl <= mid)
val += ick(p << 1, cl, cr);
if (cr >= mid + 1)
val += ick(p << 1 | 1, cl, cr);
return val;
}
int main()
{
int n, q, l, r, k;
char o;
while (~scanf("%d%d", &n,&q))
{
build(1, 1, n);
for (int i = 1; i <= q; i++)
{
cin>>o;
if(o=='C')
{
scanf("%d%d%d",&l,&r,&k);
icg(1,l,r,k);
}
else if(o=='Q')
{
scanf("%d%d",&l,&r);
printf("%lld\n",ick(1,l,r));
}
}
}
}
ED
\