题解:P17180 Canines Canines Paws Claws
简单题,但是赛时饭堂以为必须得使用矩阵加速就开摆了。
首先我们充分理解题意以后发现如果
我们让
总结一下转移式大概长这样:
接下来怎么优化?矩阵加速显然是一种好办法。但是赛后我经过深思后我决定使用动态开点线段树大法 (其实是因为不太会矩阵加速)。具体地,我们要怎么做呢?发现对于每个
意思大家自己体味一下吧,把定义搞懂这些就是显然的了。
需要注意一下的是我们还需要根据右区间的
总结来说,就是前面的拆分成四个变量有点绕,稍微花点时间就能想通了,实现上有一些小细节,并且这道题目的空间卡得巨紧,你必须尽可能地压空间(其实我卡
然后操作
先展示一下一个线段树节点需要维护的有哪些东西:
struct node{
int x1,y1,x2,y2;//分别表示 a_r 和 b_r 的含义(由几个 a_l、几个 b_l 组成)
bool len,s,tag;//长度是否等于 1(push_up 时有边界需要特判),d_l 是 1 还是 -1,懒标记
}
还有这道题目不能全开 long long,空间卡得特别紧!!!特别特别紧!
时空复杂度都是
upd:观察了一下矩阵加速的解法,发现我这种做法的本质就是矩阵加速。 :::success[code]
#include <bits/stdc++.h>
using namespace std;
using LL=long long;
#define mid (l+r>>1)
const int mod=19990721,N=17000005;
struct node{int x1,y1,x2,y2;bool len,s,tag;}tree[N];
int m,op,ans,k,lh[N],rh[N],cnt;
LL n,l,r;
inline void push_up(node &p,node L,node R){
node t=L;
if(R.s==1) (t.x1+=t.x2)%=mod,(t.y1+=t.y2)%=mod;
else (t.x2+=t.x1)%=mod,(t.y2+=t.y1)%=mod;
if(R.len!=1)
p.x1=(1ll*R.x1*t.x1+1ll*R.y1*t.x2)%mod,p.x2=(1ll*R.x2*t.x1+1ll*R.y2*t.x2)%mod,
p.y1=(1ll*R.x1*t.y1+1ll*R.y1*t.y2)%mod,p.y2=(1ll*R.x2*t.y1+1ll*R.y2*t.y2)%mod;
else p=t;
p.s=L.s,p.tag=p.len=0;
}
inline void f(node &p){swap(p.x1,p.x2),swap(p.y1,p.y2),swap(p.x1,p.y1),swap(p.x2,p.y2),p.s=p.s^1,p.tag=p.tag^1;}
inline void push_down(int p){
if(!tree[p].tag) return;
f(tree[lh[p]]);
f(tree[rh[p]]);
tree[p].tag=0;
}
inline void update(int p,LL l,LL r,LL nl,LL nr){
if(l>nr||r<nl) return;
if(l>=nl&&r<=nr){
f(tree[p]);
return;
}
if(!lh[p]) lh[p]=++cnt,tree[cnt]={1,mid-l,0,1,mid==l,1,0};
if(!rh[p]) rh[p]=++cnt,tree[cnt]={1,r-mid-1,0,1,mid+1==r,1,0};
push_down(p);
update(lh[p],l,mid,nl,nr);
update(rh[p],mid+1,r,nl,nr);
push_up(tree[p],tree[lh[p]],tree[rh[p]]);
}
inline node query(int p,LL l,LL r,LL ql,LL qr){
if(l>=ql&&r<=qr) return tree[p];
if(!lh[p]) lh[p]=++cnt,tree[cnt]={1,mid-l,0,1,mid==l,1,0};
if(!rh[p]) rh[p]=++cnt,tree[cnt]={1,r-mid-1,0,1,mid+1==r,1,0};
push_down(p);
if(mid>=qr) return query(lh[p],l,mid,ql,qr);
if(mid<ql) return query(rh[p],mid+1,r,ql,qr);
node res;
push_up(res,query(lh[p],l,mid,ql,qr),query(rh[p],mid+1,r,ql,qr));
return res;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
cnt=1;
tree[1]={1,n-1,0,1,n,1,0};
while(m--){
cin>>op>>l>>r;
l+=ans,r+=ans;
if(op==0){
l%=n,r%=n,l+=2,r+=2;
if(r>n) r--;
if(l<=r) update(1,1,n,l,r);
}
else{
l%=n,r%=n,l++,r++,cin>>k;
if(!k){
cout<<(ans=1)<<'\n';
continue;
}
if(k>1){
cout<<(ans=2)<<'\n';
continue;
}
node res=query(1,1,n,l,r);
// cout<<res.x1<<' '<<res.y1<<' '<<res.x2<<' '<<res.y2<<'\n';;
cout<<(ans=(1ll*res.x1+res.x2+res.y1+res.y2)%mod)<<'\n';
}
}
return 0;
}