>Link
luogu U137918
>Description
对于100%的数据,01串长度<=200000,N<=200000
>解题思路
对二进制数的一段进行排序的话,排出来的那一段就是形如 0000011111 或 11111100000
那我们只要知道这一段的1的个数(0的个数也可以),然后把这一段分成两个区间,分别对两个区间里所有的值赋值
然后这不就是线段树吗(麻了,真不知道我比赛的时候为什么妹想到QAQ
还有一个操作是对二进制的一段取值,那我们也可以在线段树上维护,把左儿子乘上2的右儿子的长度的次方,然后再加上右儿子就行了
改题的时候不知道为什么一直超时,后来才发现是询问的时候打错了return的条件,一直询问到了叶子节点,还是太粗心了QAQ
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctime>
#define LL long long
#define N 200010
using namespace std;
const LL Mod = 1e9 + 7;
struct node
{
LL vl; int ln;
};
int n, a[N], sum[N * 4], lazy[N * 4], len[N * 4];
LL power[N], val[N * 4];
string s;
void build (int k, int l, int r)
{
len[k] = r - l + 1;
if (l == r)
{
sum[k] = val[k] = a[l];
return;
}
int mid = (l + r) / 2;
build (k * 2, l, mid);
build (k * 2 + 1, mid + 1, r);
sum[k] = sum[k * 2] + sum[k * 2 + 1];
val[k] = (val[k * 2] * power[len[k * 2 + 1]] % Mod + val[k * 2 + 1]) % Mod;
}
void pushdown (int k)
{
if (lazy[k] == -1) return;
sum[k] = lazy[k] * len[k];
if (!lazy[k]) val[k] = 0;
else val[k] = (power[len[k]] - 1 + Mod) % Mod;
lazy[k * 2] = lazy[k * 2 + 1] = lazy[k];
lazy[k] = -1;
}
int asksum (int k, int l, int r, int ll, int rr)
{
pushdown (k);
if (ll <= l && r <= rr) return sum[k];
int mid = (l + r) / 2, ret = 0;
if (ll <= mid) ret += asksum (k * 2, l, mid, ll, rr);
if (rr >= mid + 1) ret += asksum (k * 2 + 1, mid + 1, r, ll, rr);
return ret;
}
void change (int k, int l, int r, int ll, int rr, int x)
{
if (ll <= l && r <= rr)
{
lazy[k] = x;
pushdown (k);
return;
}
pushdown (k);
pushdown (k * 2), pushdown (k * 2 + 1);
int mid = (l + r) / 2;
if (ll <= mid) change (k * 2, l, mid, ll, rr, x);
if (rr >= mid + 1) change (k * 2 + 1, mid + 1, r, ll, rr, x);
sum[k] = sum[k * 2] + sum[k * 2 + 1];
val[k] = (val[k * 2] * power[len[k * 2 + 1]] % Mod + val[k * 2 + 1]) % Mod;
}
node askval (int k, int l, int r, int ll, int rr)
//询问的区间不一定就包含整个节点,我们又要知道每个节点的要取的长度,所以要返回两个值
{
pushdown (k);
if (ll <= l && r <= rr) return (node){val[k], len[k]};
int mid = (l + r) / 2;
node p1 = (node){0, 0}, p2 = (node){0, 0}, ret;
if (ll <= mid) p1 = askval (k * 2, l, mid, ll, rr);
if (rr >= mid + 1) p2 = askval (k * 2 + 1, mid + 1, r, ll, rr);
ret.vl = (p1.vl * power[p2.ln] % Mod + p2.vl) % Mod;
ret.ln = p1.ln + p2.ln;
return ret;
}
int main()
{
memset (lazy, -1, sizeof (lazy));
int Q, opt, l, r, tot;
cin >> s;
n = s.size(), s = " " + s;
for (int i = 1; i <= n; i++) a[i] = s[i] - '0';
power[0] = 1;
for (int i = 1; i <= n; i++) power[i] = power[i - 1] * 2 % Mod;
build (1, 1, n);
scanf ("%d", &Q);
while (Q--)
{
scanf ("%d%d%d", &opt, &l, &r);
if (opt == 1)
{
tot = asksum (1, 1, n, l, r);
change (1, 1, n, l, l + tot - 1, 1);
change (1, 1, n, l + tot, r, 0);
}
else if (opt == 2)
{
tot = asksum (1, 1, n, l, r);
change (1, 1, n, l, r - tot, 0);
change (1, 1, n, r - tot + 1, r, 1);
}
else printf ("%lld\n", askval (1, 1, n, l, r).vl);
}
return 0;
}