输入:
3 5 4
1 2 3 3 1
1 3 4 5
1 2 2 4
2 3 1
1 1 2 3
输出:
2
1
6
思路: 线段树维护操作结果
首先明确对于平衡二叉树,每个结点编号的二进制代表着它从1走到所处位置的路径,其中0代表左儿子,1表示右儿子,第一个1是根结点,比如:对于结点5,它的二进制是101,它从1 -> 1的左儿子2 -> 2的右儿子5,分别对应101, 所以可以用数字表示路径,路径之间也有可加性,例如:2+3=5,在2这个结点,只需将从1走到3的路径,复制到2这个结点身上,就可以到5了,相当于将2看作根节点。
维护三个信息:
(1)区间操作中能到达的最高祖先
(2)最深深度
(3)路径
前两个信息维护的原因不赘述,说一下第三个信息,因为可能落在右儿子上,通过前两个信息只能知道终点的深度,不能知道具体在哪棵树上,所以设置个路径变量维护具体位置。
具体操作:假设合并区间a和b,可以发现假设终点深度为d,此时d层有2的d-1次方棵子树,合并的时候,如果终点落在左还是右儿子与区间a无关(即b最高祖先≥a最深深度),最终路径即为区间b的路径;若a区间路径有影响,则将路径通过区间b的改变移动到相应子树某儿子上,详见代码,(看代码就理解了
//几个注意点
//自定义函数里结构体初始化,比如find里的res结构体
//全局里的结构体初始化是0
//位运算一定加上括号,左右儿子还是用2*p,2*p+1写,鬼知道用位运算犯个糊涂要debug多久
//对结构体初始化操作,tree[p] = (ty){0,0,0};(之前课设就可以用
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(x,y) memset(x,y,sizeof(x))
#define all(v) v.begin() , v.end()
#define pb(v) push_back(v)
#define INF 0x3f3f3f3f
#define int long long
#define lson p*2,l,mid
#define rson p*2+1,mid+1,r
typedef long long ll;
const int N = 5e5+10;
int a[N];
int n,m,q;
struct ty
{
int f;//最高祖先
int dp;//最深深度
int num;//路径,每个数字都代表一条路,路径间具有可加性
ty operator + (const ty &b)const//区间合并直接对+重定义,分两大类,合并后b对num有无影响
{
ty ans;
//区间为空的时候可以合并到下面两类
// if( !f && !dp)
// {
// return b;
// }
// else if( !b.f && !b.dp )
// {
// return *this;
// }
if( dp <= b.f)//num路径被b改变,num对最终路径无贡献
{
ans.num = b.num;
ans.f = f - dp + b.f;
ans.dp = b.dp;
}
else//n最终路径受b的影响叠加
{
ans.num = ( (num>>b.f)<<b.dp ) + b.num;
ans.f = f;
ans.dp = dp - b.f + b.dp;
}
return ans;
}
}tree[N*4];
void build(int p ,int l, int r )
{
if( l==r )
{
if( a[l] <=2 )
{
tree[p].dp = 1;
}
if( a[l] == 2)
{
tree[p].num = 1;
}
if( a[l] == 3)
{
tree[p].f=1;
}
return ;
}
int mid = (l+r)>>1;
build(lson);
build(rson);
tree[p] = tree[2*p] + tree[2*p+1];
cout<<" p l r f dp num "<<p<<" "<<l<<" "<<r<<" "<<tree[p].f<<" "<<tree[p].dp<<" "<<tree[p].num<<endl;
}
void change(int p, int l, int r ,int x ,int y)
{
if(l == r)
{
tree[p] = (ty){0,0,0};
if( y <=2 )
{
tree[p].dp = 1;
}
if( y == 2)
{
tree[p].num = 1;
}
if( y == 3)
{
tree[p].f=1;
}
return;
}
int mid = (l+r)>>1;
if( x<= mid ) change(lson,x,y);
else change(rson,x,y);
tree[p] = tree[2*p] + tree[2*p+1];
}
ty find(int p ,int l ,int r ,int a, int b)
{
if( a <= l && r <= b)
{
return tree[p];
}
ty res=(ty){0,0,0};
int mid = (l+r)>>1;
if( a<=mid ) res = find(lson,a,b);
if( b>=mid+1 ) res = res + find(rson,a,b);
return res;
}
signed main()
{
IOS;
cin>>n>>m>>q;
_for(i,1,m)
cin>>a[i];
build(1,1,m);
_for(i,1,q)
{
int op,l,r,s,x,y;
ty node;
cin>>op;
if( op == 1)
{
cin>>s>>l>>r;
node = find(1,1,m,l,r);//查询操作
s = (( max((s>>node.f),1ll) )<<node.dp )+node.num;//执行操作
cout<<s<<endl;
}
else
{
cin>>x>>y;
change(1,1,m,x,y);//修改值
}
}
}