题意
给n个区间S_i =
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri],n-1个集合操作
o
p
i
=
{
∪
,
∩
,
⊕
}
op_i=\{\cup,\cap,\oplus\}
opi={∪,∩,⊕}.求
∣
(
.
.
.
(
(
S
1
o
p
1
S
2
)
o
p
3
S
3
)
.
.
.
)
o
p
n
−
1
S
n
∣
|(...((S_1\;op_1\;S_2)\;op_3\;S_3)...)\;op_{n-1}\;S_{n}|
∣(...((S1op1S2)op3S3)...)opn−1Sn∣
即所有可能操作结果的区间长度总和
constrains:
1
≤
n
≤
3
e
5
1\leq n\leq 3e5
1≤n≤3e5
0
≤
l
i
≤
r
i
≤
3
e
5
0\leq l_i\leq r_i\leq3e5
0≤li≤ri≤3e5
思路
考虑独立贡献,数轴上每一个点都是可以贡献的单位,比如,
x
x
x这一点的贡献为
1
∗
(
x
这一点在结果区间的方案数
)
1*(x这一点在结果区间的方案数)
1∗(x这一点在结果区间的方案数),把包含x的区间记为1,否则为0,例如[0,0,0,1,1,1,1,0]中8个区间中4~7的区间包含
x
x
x,方案数可以用
d
p
(
i
,
j
)
dp(i,j)
dp(i,j)简单计算,
d
p
(
i
,
j
)
dp(i,j)
dp(i,j)表示操作完前
i
i
i个区间时,结果中
x
x
x位为
j
∈
{
0
,
1
}
j\in \{0,1\}
j∈{0,1}的方案数.有如下线性转移
若s[i]包含
x
x
x,
d
p
(
i
,
1
)
=
2
d
p
(
i
−
1
,
0
)
+
2
d
p
(
i
−
1
,
1
)
,
d
p
(
i
,
0
)
=
d
p
(
i
−
1
,
0
)
+
d
p
(
i
−
1
,
1
)
dp(i,1)=2dp(i-1,0)+2dp(i-1,1),dp(i,0)=dp(i-1,0)+dp(i-1,1)
dp(i,1)=2dp(i−1,0)+2dp(i−1,1),dp(i,0)=dp(i−1,0)+dp(i−1,1)
若不包含,
d
p
(
i
,
1
)
=
2
d
p
(
i
−
1
,
1
)
,
d
p
(
i
,
0
)
=
d
p
(
i
−
1
,
1
)
+
3
d
p
(
i
−
1
,
0
)
dp(i,1)=2dp(i-1,1),dp(i,0)=dp(i-1,1)+3dp(i-1,0)
dp(i,1)=2dp(i−1,1),dp(i,0)=dp(i−1,1)+3dp(i−1,0)
我们不可能对0~3e5每个位置这样dp,太慢了,我就打表看结果有没有规律,发现有…记最后一个包含
x
x
x的区间下标为
k
k
k,则贡献为
3
k
−
2
∗
2
n
−
k
+
1
,
k
=
1
3^{k-2}*2^{n-k+1},k=1
3k−2∗2n−k+1,k=1是比较特别的(
S
1
S_1
S1没法操作),特判一下.组合含义解释
k
k
k前面的
o
p
op
op任选的情况下,要么现在含x要么不含,对于两种情况,k都有两种操作使得结果含x,k后面的区间只要不取
∩
\cap
∩即可.所以我们用线段树维护包含某一个点的最后一个区间的下标即可.
答案的做法可能更符合一条顺畅的思路,但我线段树造诣不够,没想到.
d
p
dp
dp这个递推很容易想到矩阵快速幂,因为是线性的转移,就是说当加入一个区间时,我们对于该区间包含的点的
d
p
(
i
,
1
)
,
d
p
(
i
,
0
)
dp(i,1),dp(i,0)
dp(i,1),dp(i,0)作一次矩阵乘法操作即可,就是说线段树维护的是矩阵,乘法也是矩阵,操作完所有区间后,就得到了每一个点的最终dp结果.代码待补…
单点修改,pushup是一个转移矩阵的累乘,用差分的办法,每次只修改左右端点线段树上的值(累乘一个新的转移矩阵)
树长度为n,区间数,从0~3e5遍历数轴,数轴上每一个点的贡献由整颗树的根得来,不同的点对应的树需要修改,但总共修改O(n)次,假设当前处理i,树节点x表示区间x对于i的转移矩阵,(如果区间x包含i则为ONE,否则为ZERO),那么i的贡献就是所有节点值的连乘(dp的过程),就是树的根节点的值,考虑i+1,我们需要记录i+1上的是否是某些区间的右端点+1,是的话就把该区间的树节点置ZERO,是否有某些区间的左端点,是的话就把那些区间的树节点值改为ONE,有点像差分里面的消除影响
单点修改O(logn)+区间查询O(1)
我的是区间修改+单点查询,更慢.
代码
我的
#include<bits/stdc++.h>
using namespace std;
#define pow2(X) (1ll<<(X))
#define SIZE(A) ((int)A.size())
#define LENGTH(A) ((int)A.length())
#define ALL(A) A.begin(),A.end()
#define F(i,a,b) for(ll i=a;i<=(b);++i)
#define dF(i,a,b) for(ll i=a;i>=(b);--i)
#define GETPOS(c,x) (lower_bound(ALL(c),x)-c.begin())
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3f
#define pb push_back
#define pr pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define eps 1e-6
#define PI acos(-1.0)
#define lb lower_bound
#define ub upper_bound
#define bs binary_search
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);}
#define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);}
#define es(x,e) (int e=fst[x];e;e=nxt[e])
#define esb(x,e,b) (int e=fst[x],b=vb[e];e;e=nxt[e],b=vb[e])
#define SZ 666666
typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> ipair;
typedef vector<int> VI;
typedef vector<long long> VLL;
typedef vector<vector<long long > > VVLL;
typedef vector<vector<int> > VVI;
typedef vector<double> VD;
typedef vector<string> VS;
const int mods = 998244353;
//const int mods = 1e9+7;
const int maxn = 3e5+10;
const int N = 5e5+10;
const int E = 1e4+10;
const int lim = 1e6+10;
ll qpow(ll a,ll b) {ll res=1;a%=mods; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mods;a=a*a%mods;}return res;}
ll lcm(ll a, ll b) {return a / __gcd(a, b) * b;}
int read(){ll 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*10+ch-'0';ch=getchar();}return x*f;}
/***********************************
learning time
***********************************/
int n,m;
int l[maxn],r[maxn];
ll maa[maxn<<2],lazy[maxn<<2];
void pushup(int rt) {
maa[rt] = max(maa[rt << 1],maa[rt << 1 | 1]);
}
//赋值版
void pushdown(int rt) {
if (lazy[rt]) {
maa[rt << 1] = lazy[rt];
maa[rt << 1 | 1] = lazy[rt];
lazy[rt << 1] = lazy[rt];
lazy[rt << 1 | 1] = lazy[rt];
lazy[rt] = 0;
}
}
void update(int L, int R, int l, int r, int rt,ll C) {
if (L <= l && r <= R) {
maa[rt] = C;
lazy[rt] = C;
return;
}
int mid = (l + r) >> 1;
pushdown(rt);
if (L <= mid) update(L, R, l, mid, rt << 1,C);
if (R > mid) update(L, R, mid + 1, r, rt << 1 | 1,C);
pushup(rt);
}
ll query_sum(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) {
return maa[rt];
}
int mid = (l + r) >> 1;
pushdown(rt);
ll ans = 0;
if (L <= mid) ans = max(ans,query_sum(L,R,l,mid,rt<<1));
if (R > mid) ans = max(ans,query_sum(L, R, mid + 1, r, rt << 1 | 1));
return ans;
}
int main(){
// freopen("C:\\Users\\Gao\\Desktop\\validation_input\\watering_well_chapter_2_input.txt","r",stdin);
// freopen("C:\\Users\\Gao\\Desktop\\validation_input\\output.txt","w",stdout);
ios_base::sync_with_stdio(0);
int T;
//cin>>T;
T = 1;
F(turn,1,T){
m = 1;
cin>>n;
F(i,1,n){
cin>>l[i]>>r[i];
l[i]++;r[i]++;
m = max(m,r[i]);
}
ll ans = 0;
F(i,1,n){
int lef = l[i],rig = r[i];
update(lef,rig,1,m,1,i);
}
F(i,1,m){
ll k = query_sum(i,i,1,m,1);
//cout<<i<<" "<<k<<endl;
if(k>1)
(ans+=qpow(3,k-2)*qpow(2,n-k+1)%mods)%=mods;
else if(k==1){
(ans+=qpow(2,n-k))%=mods;
}
}
cout<<ans<<endl;
}
}
/*
*/
答案
#include<bits/stdc++.h>
using namespace std;
const int N = 300043;
typedef array<int, 2> vec;
typedef array<vec, 2> mat;
const int MOD = 998244353;
mat operator*(const mat& a, const mat& b)
{
mat c;
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++)
c[i][j] = 0;
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++)
for(int k = 0; k < 2; k++)
c[i][k] = (a[i][j] * 1ll * b[j][k] + c[i][k]) % MOD;
return c;
}
mat ZERO = {vec({3, 0}), vec({1, 2})};
mat ONE = {vec({1, 2}), vec({1, 2})};
mat t[4 * N];
void recalc(int v)
{
t[v] = t[v * 2 + 1] * t[v * 2 + 2];
}
void build(int v, int l, int r)
{
if(l == r - 1)
{
t[v] = ZERO;
}
else
{
int m = (l + r) / 2;
build(v * 2 + 1, l, m);
build(v * 2 + 2, m, r);
recalc(v);
}
}
void upd(int v, int l, int r, int pos, int val)
{
if(l == r - 1)
{
if(val == 0) t[v] = ZERO;
else t[v] = ONE;
}
else
{
int m = (l + r) / 2;
if(pos < m) upd(v * 2 + 1, l, m, pos, val);
else upd(v * 2 + 2, m, r, pos, val);
recalc(v);
}
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
int n;
cin >> n;
vector<vector<pair<int, int>>> v(N);
for(int i = 0; i < n; i++)
{
int l, r;
cin >> l >> r;
v[l].push_back(make_pair(1, i));
v[r + 1].push_back(make_pair(0, i));
}
build(0, 0, n - 1);
int cur = 0;
int ans = 0;
for(int i = 0; i <= 300000; i++)
{
for(auto x : v[i])
{
if(x.second == 0) cur = x.first;
else upd(0, 0, n - 1, x.second - 1, x.first);
}
ans = (ans + t[0][cur][1]) % MOD;
}
cout << ans << endl;
}