[Ynoi2007]rfplca

rfplca

题解

看到这种恶心的序列区间操作应该很容易想到通过分块来进行维护。好像也不能用什么线段树之类的
我们考虑对于同一个块里每个点最远能跳到该块内的那个点,再跳就跳出去了。
很显然,我们每对一个块进行一次修改就会让该块内的更多的点再跳一次就跳出去,毕竟 a i a_{i} ai是不断减少的。
而一个点如果想要跳出该块,显然我们对其进行进行的操作是不会超过 S S S即块长次的。
所以我们对一个块的整体修改操作次数是不会超过 S S S的,之后的话就暴力记录下来该块被整体操作了多少次,在跳的时候对其的 a i a_{i} ai减去 l z y b l o c k i lzy_{block_{i}} lzyblocki即可。
我们每次查询的话就可以一个块一个块的跳,直到找到它们的 l c a lca lca为止,毕竟我们是处理出每个点在块内最远跳到那里的。

时间复杂度显然是 O ( n S + n m S ) ⩾ O ( n 2 m 3 ) ≈ O ( ( n + m ) n ) O\left(nS+\frac{nm}{S}\right)\geqslant O\left(\sqrt[3]{n^2m}\right)\approx O\left((n+m)\sqrt{n}\right) O(nS+Snm)O(3n2m )O((n+m)n )

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 400010
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;     
const LL INF=0x3f3f3f3f3f3f3f3f;  
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int n1=300;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){putchar('\n');while(x>9){putchar((x%10)|'0');x/=10;}putchar(x|'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
const int M=MAXN/n1+5;
int n,q,a[MAXN],block[MAXN],L[M],R[M],nxt[MAXN],lzy[M],lans;
void TagBlock(int x){for(int i=L[x];i<=R[x];i++)a[i]=max(a[i]-lzy[x],1);lzy[x]=0;}
void SetBlock(int x){for(int i=L[x];i<=R[x];i++)if(a[i]<L[x])nxt[i]=i;else nxt[i]=nxt[a[i]];}
signed main(){
	read(n);read(q);for(int i=2;i<=n;i++)read(a[i]);
	for(int i=1;i<=n;i++)block[i]=(i+n1-1)/n1;
	for(int i=1;i<=n;i++){if(!L[block[i]])L[block[i]]=i;R[block[i]]=i;}
	for(int i=1;i<=block[n];i++)SetBlock(i);
	for(int i=1;i<=q;i++){
		int opt;read(opt);
		if(opt==1){
			int l,r,x;read(l);read(r);read(x);l^=lans;r^=lans;x^=lans;
			if(block[l]==block[r]){
				TagBlock(block[l]);
				for(int j=l;j<=r;j++)a[j]=max(a[j]-x,1);
				SetBlock(block[l]);
			}
			else{
				TagBlock(block[l]);for(int j=l;j<=R[block[l]];j++)a[j]=max(a[j]-x,1);SetBlock(block[l]);
				TagBlock(block[r]);for(int j=L[block[r]];j<=r;j++)a[j]=max(a[j]-x,1);SetBlock(block[r]);
				for(int j=block[l]+1;j<block[r];j++)lzy[j]=min(lzy[j]+x,n);
			}
		}
		else{
			int u,v;read(u);read(v);u^=lans;v^=lans;
			while(u^v){
				if(block[u]<block[v])swap(u,v);
				if(block[u]^block[v]){
					if((nxt[u]^u)&&lzy[block[u]])
						TagBlock(block[u]),SetBlock(block[u]);
					u=max(a[nxt[u]]-lzy[block[u]],1);
				}
				else{
					if(((nxt[u]^u)||(nxt[v]^v))&&lzy[block[u]])
						TagBlock(block[u]),SetBlock(block[u]);
					if(nxt[u]^nxt[v])u=max(a[nxt[u]]-lzy[block[u]],1),v=max(a[nxt[v]]-lzy[block[v]],1);
					else while(u^v){if(u<v)swap(u,v);u=a[u];}
				}
			}
			printf("%d\n",lans=u);
		}
	}
	return 0;
}

谢谢!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值