数据结构练习
[NOI2021] 密码箱
这么说Quack大爷就有队爷水平了
首先考虑\(f\)是个线性变换
这里对于\(\dfrac{x}{y}\rightarrow \dfrac{y}{x}+a_i\),第\(i\)个元素可以用矩阵表示
\[\left [ \begin{matrix} x& y \\ 0& 0 \\ \end{matrix} \right ] \times\left [ \begin{matrix} a_i& 1 \\ 1& 0 \\ \end{matrix} \right ] \]于是这里我们可以把序列拉成一个矩阵,但这是不够的,因为原题要对操作序列操作
考虑把每个操作也看作矩阵
对于\(W\),很明显就是左乘
\[\left [ \begin{matrix} 1& 1 \\ 0& 1 \\ \end{matrix} \right ] \]对于\(E\),手完一下就能发现其实都可以看作减一后在后面填两个数
那其实就相当于左乘
\[\left [ \begin{matrix} 1& 1 \\ 1& 0 \\ \end{matrix} \right ]\times\left [ \begin{matrix} 1& 1 \\ 1& 0 \\ \end{matrix} \right ]\times \left [ \begin{matrix} 1& -1 \\ 0& 1 \\ \end{matrix} \right ]=\left [ \begin{matrix} 2& -1 \\ 1& 0 \\ \end{matrix} \right ] \]用平衡树维护即可,细节有点多
#include<bits/stdc++.h>
#define ls Tree[p].lc
#define rs Tree[p].rc
using namespace std;
void read(int &x) {
x = 0;
int f = 1;
char s = getchar();
while (s > '9' || s < '0') {
if (s == '-')
f = -1;
s = getchar();
}
while (s >= '0' && s <= '9') {
x = (x << 3) + (x << 1) + (s - '0');
s = getchar();
}
x *= f;
}
void write(int x) {
if (x < 0) {
putchar('-');
x = (~x) + 1;
}
if (x > 9) {
write(x / 10);
}
putchar(x % 10 + '0');
}
const int MOD=998244353;
const int MAXN=2e5+5;
struct Martix{
int val[2][2];
void clear()
{
memset(val,0,sizeof(val));
}
void init()
{
clear();
for(int i=0;i<2;i++)
{
val[i][i]=1;
}
return;
}
void print()
{
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
printf("%d ",val[i][j]);
}
printf("\n");
}
printf("\n");
}
Martix operator*(const Martix x)const{
Martix Res;
Res.clear();
for(int k=0;k<2;k++)
{
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
Res.val[i][j]=((long long)Res.val[i][j]+((long long)val[i][k]*x.val[k][j])%MOD)%MOD;
}
}
}
return Res;
}
}A,B,C;
struct FHQ_node{
int lc,rc;
int cnt;
int Siz;
int Key;
Martix dt[2][2],val[2];
int lazy_rev;
int lazy_roll;
};
struct FHQ{
FHQ_node Tree[MAXN];
int root;
int cnt_node;
int New(int op)
{
++cnt_node;
Tree[cnt_node].cnt=1;
Tree[cnt_node].Siz=1;
Tree[cnt_node].lazy_rev=0;
Tree[cnt_node].lazy_roll=0;
Tree[cnt_node].lc=0;
Tree[cnt_node].rc=0;
Tree[cnt_node].Key=rand();
Tree[cnt_node].dt[op][0]=Tree[cnt_node].dt[op][1]=Tree[cnt_node].val[op]=A;
Tree[cnt_node].dt[op^1][0]=Tree[cnt_node].dt[op^1][1]=Tree[cnt_node].val[op^1]=B;
return cnt_node;
}
void push_up(int p)
{
Tree[p].Siz=Tree[ls].Siz+Tree[rs].Siz+Tree[p].cnt;
Tree[p].dt[0][0].init();
if(ls)
{
Tree[p].dt[0][0]=Tree[p].dt[0][0]*Tree[ls].dt[0][0];
}
Tree[p].dt[0][0]=(Tree[p].dt[0][0]*Tree[p].val[0]);
if(rs)
{
Tree[p].dt[0][0]=Tree[p].dt[0][0]*Tree[rs].dt[0][0];
}
Tree[p].dt[1][0].init();
if(ls)
{
Tree[p].dt[1][0]=Tree[p].dt[1][0]*Tree[ls].dt[1][0];
}
Tree[p].dt[1][0]=(Tree[p].dt[1][0]*Tree[p].val[1]);
if(rs)
{
Tree[p].dt[1][0]=Tree[p].dt[1][0]*Tree[rs].dt[1][0];
}
Tree[p].dt[0][1].init();
if(rs)
{
Tree[p].dt[0][1]=Tree[p].dt[0][1]*Tree[rs].dt[0][1];
}
Tree[p].dt[0][1]=(Tree[p].dt[0][1]*Tree[p].val[0]);
if(ls)
{
Tree[p].dt[0][1]=Tree[p].dt[0][1]*Tree[ls].dt[0][1];
}
Tree[p].dt[1][1].init();
if(rs)
{
Tree[p].dt[1][1]=Tree[p].dt[1][1]*Tree[rs].dt[1][1];
}
Tree[p].dt[1][1]=(Tree[p].dt[1][1]*Tree[p].val[1]);
if(ls)
{
Tree[p].dt[1][1]=Tree[p].dt[1][1]*Tree[ls].dt[1][1];
}
}
void push_down(int p)
{
if(Tree[p].lazy_roll)
{
swap(ls,rs);
swap(Tree[ls].dt[0][0],Tree[ls].dt[0][1]);
swap(Tree[ls].dt[1][0],Tree[ls].dt[1][1]);
swap(Tree[rs].dt[0][0],Tree[rs].dt[0][1]);
swap(Tree[rs].dt[1][0],Tree[rs].dt[1][1]);
Tree[ls].lazy_roll^=1;
Tree[rs].lazy_roll^=1;
Tree[p].lazy_roll=0;
}
if(Tree[p].lazy_rev)
{
swap(Tree[ls].dt[0][0],Tree[ls].dt[1][0]);
swap(Tree[ls].dt[0][1],Tree[ls].dt[1][1]);
swap(Tree[ls].val[0],Tree[ls].val[1]);
swap(Tree[rs].dt[0][0],Tree[rs].dt[1][0]);
swap(Tree[rs].dt[0][1],Tree[rs].dt[1][1]);
swap(Tree[rs].val[0],Tree[rs].val[1]);
Tree[ls].lazy_rev^=1;
Tree[rs].lazy_rev^=1;
Tree[p].lazy_rev=0;
}
}
void Split(int p,int val,int &x,int &y)
{
if(!p)
{
x=0;
y=0;
return;
}
push_down(p);
if(Tree[ls].Siz+Tree[p].cnt<=val)
{
x=p;
Split(rs,val-Tree[ls].Siz-Tree[p].cnt,rs,y);
}
else
{
y=p;
Split(ls,val,x,ls);
}
push_up(p);
}
int Merge(int x,int y)
{
if((!x)||(!y))
{
return x+y;
}
if(Tree[x].Key<Tree[y].Key)
{
push_down(x);
Tree[x].rc=Merge(Tree[x].rc,y);
push_up(x);
return x;
}
else
{
push_down(y);
Tree[y].lc=Merge(x,Tree[y].lc);
push_up(y);
return y;
}
}
void Insert(int op)
{
root=Merge(root,New(op));
return;
}
void Rev(int l,int r)
{
int lx,zx,rx;
Split(root,l-1,lx,rx);
Split(rx,r-l+1,zx,rx);
swap(Tree[zx].dt[0][1],Tree[zx].dt[1][1]);
swap(Tree[zx].dt[0][0],Tree[zx].dt[1][0]);
swap(Tree[zx].val[0],Tree[zx].val[1]);
Tree[zx].lazy_rev^=1;
root=Merge(lx,Merge(zx,rx));
return;
}
void Roll(int l,int r)
{
int lx,zx,rx;
Split(root,l-1,lx,rx);
Split(rx,r-l+1,zx,rx);
swap(Tree[zx].dt[0][0],Tree[zx].dt[0][1]);
swap(Tree[zx].dt[1][0],Tree[zx].dt[1][1]);
Tree[zx].lazy_roll^=1;
root=Merge(lx,Merge(zx,rx));
return;
}
}tree;
int n,q;
char S[MAXN];
char R[15];
int l,r;
int main()
{
freopen("code.in","r",stdin);
freopen("code.out","w",stdout);
srand(time(0));
A.val[0][0]=1;
A.val[0][1]=1;
A.val[1][0]=0;
A.val[1][1]=1;
B.val[0][0]=2;
B.val[0][1]=MOD-1;
B.val[1][0]=1;
B.val[1][1]=0;
C.val[0][0]=1;
C.val[0][1]=1;
C.val[1][0]=1;
C.val[1][1]=0;
read(n);
read(q);
scanf("%s",S);
for(int i=0;i<n;i++)
{
if(S[i]=='W')
{
tree.Insert(0);
}
else
{
tree.Insert(1);
}
}
printf("%d %d\n",(tree.Tree[tree.root].dt[0][1]*C).val[0][1],(tree.Tree[tree.root].dt[0][1]*C).val[0][0]);
while(q--)
{
scanf("%s",R);
if(R[0]=='A')
{
scanf("%s",R);
if(R[0]=='W')
{
tree.Insert(0);
}
else
{
tree.Insert(1);
}
}
else if(R[0]=='F')
{
read(l);
read(r);
tree.Rev(l,r);
}
else
{
read(l);
read(r);
tree.Roll(l,r);
}
printf("%d %d\n",(tree.Tree[tree.root].dt[0][1]*C).val[0][1],(tree.Tree[tree.root].dt[0][1]*C).val[0][0]);
}
}
CF1588F Jumping Through the Array
这个条件看着很奇怪,不妨往分块上想
进一步,考虑操作分块
考虑如果没有操作\(3\),这里我们可以发现涉及到的环只有\(\sqrt n\)
这里我们就可以暴力计算每个操作对每个询问的影响,最后\(\sqrt n\)次暴力推平即可
如果有操作三,我们可以对点染色,可以发现每个交换点的前驱是跟在它一起的
实际上我们可以把它的极长空白前驱放在一起为一个联通块
这里对于操作\(2\)这里我们操作一次大概是直接走前驱,只有\(\sqrt n\)次
然后似乎就完了,注意实现,有点卡常
#include<bits/stdc++.h>
void read(int &x) {
x = 0;
int f = 1;
char s = getchar();
while (s > '9' || s < '0') {
if (s == '-')
f = -1;
s = getchar();
}
while (s >= '0' && s <= '9') {
x = (x << 3) + (x << 1) + (s - '0');
s = getchar();
}
x *= f;
}
void write(int x) {
if (x < 0) {
putchar('-');
x = (~x) + 1;
}
if (x > 9) {
write(x / 10);
}
putchar(x % 10 + '0');
}
using namespace std;
const int MAXN=2e5+5;
int n,q;
long long a[MAXN];
long long sum[MAXN];
int P[MAXN];
int S[MAXN];
int clo[MAXN];
long long Add[MAXN];
struct Query{
int op,l,r;
int x,y;
}query[MAXN];
int op,l,r,x,y;
int Rk[1005];
int Tk[MAXN];
int Sz[1005][1005];
int Tot[MAXN];
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d",&n);
int Block=430;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i];
}
for(int i=1;i<=n;i++)
{
read(P[i]);
S[P[i]]=i;
}
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
read(op);
if(op==1)
{
read(l);
read(r);
query[i].op=1;
query[i].l=l;
query[i].r=r;
}
else if(op==2)
{
read(x);
read(y);
query[i].op=2;
query[i].x=x;
query[i].y=y;
}
else if(op==3)
{
read(x);
read(y);
query[i].op=3;
query[i].x=x;
query[i].y=y;
}
}
for(int L=1;L<=q;L+=Block)
{
int R=min(L+Block-1,q);
for(int i=0;i<=n;i++)
{
clo[i]=0;
Tk[i]=0;
}
for(int i=L;i<=R;i++)
{
if(query[i].op==2)
{
clo[query[i].x]=query[i].x;
}
if(query[i].op==3)
{
clo[query[i].x]=query[i].x;
clo[query[i].y]=query[i].y;
}
}
int cnt_clo=0;
for(int i=1;i<=n;i++)
{
if(clo[i]==i)
{
Rk[++cnt_clo]=i;
int Now=S[i];
while((!clo[Now]))
{
clo[Now]=i;
Now=S[Now];
}
}
}
int cnt_q=0;
for(int i=L;i<=R;i++)
{
if(query[i].op==1)
{
Tk[query[i].l-1]=++cnt_q;
Tk[query[i].r]=++cnt_q;
}
}
if(Tk[0])
{
for(int i=1;i<=cnt_clo;i++)
{
Sz[Tk[0]][i]=0;
}
}
for(int i=1;i<=n;i++)
{
Tot[clo[i]]++;
if(Tk[i])
{
for(int j=1;j<=cnt_clo;j++)
{
Sz[Tk[i]][j]=Tot[Rk[j]];
}
}
}
for(int i=L;i<=R;i++)
{
if(query[i].op==1)
{
l=query[i].l;
r=query[i].r;
long long Rp=(sum[r]-sum[l-1]);
for(int j=1;j<=cnt_clo;j++)
{
int Pl=Sz[Tk[l-1]][j];
int Pr=Sz[Tk[r]][j];
int Ln=Pr-Pl;
Rp=(Rp+((long long)Ln*Add[Rk[j]]));
}
printf("%lld\n",Rp);
}
else if(query[i].op==2)
{
int Now=clo[P[query[i].x]];
while(1)
{
Add[Now]+=query[i].y;
if(Now==clo[query[i].x])
{
break;
}
Now=clo[P[Now]];
}
}
else
{
swap(P[query[i].x],P[query[i].y]);
S[P[query[i].x]]=query[i].x;
S[P[query[i].y]]=query[i].y;
}
}
for(int i=1;i<=n;i++)
{
a[i]=a[i]+Add[clo[i]];
sum[i]=sum[i-1]+a[i];
}
for(int i=1;i<=n;i++)
{
Add[i]=0;
Rk[min(i,1000)]=0;
Tot[i]=0;
}
}
}
CF679E Bear and Bad Powers of 42
维护每个数到下一个\(42\)次幂的距离
可以发现直接看每次加的是否会超出当前距离的最小值
超出了就暴力改,可以发现每个元素改的次数很少
具体时间复杂度分析就是把线段树每个节点还可以改多少看作势能,可以发现每次会用\(O(1)\)的时间解决\(O(1)\)的势能,而一次赋值只会增加\(O(\log_2(n))\)的势能
注意实现,好像有点卡常
我要做DJ小姐的狗·
#include<bits/stdc++.h>
#define int long long
#define ls 2*p
#define rs 2*p+1
using namespace std;
const int MAXN=1e5+5;
int n,q;
long long a[MAXN];
long long R[MAXN];
int op,l,r,x;
long long B[15];
struct Seg{
int l,r;
long long date;
long long Ori_lazy;
long long Add;
long long Ori;
}Tree[MAXN*4];
int get(int x) {
return *lower_bound(B, B + 12, x) - x;
}
void push_up(int p)
{
Tree[p].date=min(Tree[ls].date,Tree[rs].date);
}
void push_down(int p)
{
if(Tree[p].Ori_lazy!=0)
{
Tree[ls].Add=0;
Tree[rs].Add=0;
Tree[ls].Ori_lazy=Tree[p].Ori_lazy;
Tree[rs].Ori_lazy=Tree[p].Ori_lazy;
Tree[ls].date=get(Tree[p].Ori_lazy);
Tree[rs].date=get(Tree[p].Ori_lazy);
Tree[ls].Ori=Tree[p].Ori_lazy;
Tree[rs].Ori=Tree[p].Ori_lazy;
Tree[p].Ori_lazy=0;
}
if(Tree[p].Add!=0)
{
Tree[ls].date-=Tree[p].Add;
Tree[ls].Ori+=Tree[p].Add;
if(Tree[ls].Ori_lazy!=0)
{
Tree[ls].Ori_lazy+=Tree[p].Add;
}
else
{
Tree[ls].Add+=Tree[p].Add;
}
Tree[rs].date-=Tree[p].Add;
Tree[rs].Ori+=Tree[p].Add;
if(Tree[rs].Ori_lazy!=0)
{
Tree[rs].Ori_lazy+=Tree[p].Add;
}
else
{
Tree[rs].Add+=Tree[p].Add;
}
Tree[p].Add=0;
}
}
void Build(int p,int l,int r)
{
Tree[p].l=l;
Tree[p].r=r;
Tree[p].Add=0;
Tree[p].Ori_lazy=0;
if(l==r)
{
Tree[p].date=R[l];
Tree[p].Ori=a[l];
return;
}
int mid=(l+r)>>1;
Build(ls,l,mid);
Build(rs,mid+1,r);
push_up(p);
}
void Update_add(int p,int l,int r,int x)
{
if(Tree[p].l>=l&&Tree[p].r<=r)
{
Tree[p].Ori += x;
Tree[p].date-=x;
if(Tree[p].Ori_lazy!=0)
{
Tree[p].Ori_lazy+=x;
}
else
{
Tree[p].Add+=x;
}
return;
}
push_down(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
if(l<=mid)
{
Update_add(ls,l,r,x);
}
if(r>mid)
{
Update_add(rs,l,r,x);
}
push_up(p);
}
void Update_fill(int p,int l,int r,int x)
{
if(Tree[p].l>=l&&Tree[p].r<=r)
{
Tree[p].Add=0;
Tree[p].Ori=x;
Tree[p].Ori_lazy=x;
Tree[p].date=get(x);
return;
}
push_down(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
if(l<=mid)
{
Update_fill(ls,l,r,x);
}
if(r>mid)
{
Update_fill(rs,l,r,x);
}
push_up(p);
}
long long Query(int p,int x)
{
if(Tree[p].l==Tree[p].r)
{
return Tree[p].Ori;
}
push_down(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
if(x<=mid)
{
return Query(ls,x);
}
else
{
return Query(rs,x);
}
}
void upd(int p) {
if (Tree[p].date >= 0) {
return ;
} else if (Tree[p].l == Tree[p].r) {
Tree[p].date = get(Tree[p].Ori);
return ;
}
push_down(p);
upd(p << 1);
upd(p << 1 | 1);
push_up(p);
}
signed main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
B[0]=1;
for(int i=1;i<=11;i++)
{
B[i]=((long long)B[i-1]*42);
}
scanf("%lld %lld",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
int Tp=lower_bound(B,B+11+1,a[i])-B;
R[i]=B[Tp]-a[i];
}
int Cnt=0;
Build(1,1,n);
while(q--)
{
scanf("%lld",&op);
if(op==1)
{
scanf("%lld",&x);
printf("%lld\n",Query(1,x));
}
else if(op==2)
{
scanf("%lld %lld %lld",&l,&r,&x);
Update_fill(1,l,r,x);
}
else
{
scanf("%lld %lld %lld",&l,&r,&x);
Update_add(1,l,r,x);
upd(1);
while(Tree[1].date==0)
{
Update_add(1,l,r,x);
upd(1);
}
}
}
}
[UR19]前进四
维护单调栈有一个\(log^2(n)\)的做法,这里肯定是不能再优化的
于是这里我们可以换一个角度看待问题
不妨枚举位置维护每个询问
考虑这里的单调栈的过程,我们发现从后往前,只要新添加的数小于当前最小值就会使答案\(+1\)
考虑用线段树维护时间轴,区间取\(min\)即可,似乎势能线段树只取\(min\)的时间复杂度是\(O(log(n))\)的
话说4道题卡了3道题的常
#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#pragma GCC optimize("Og")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#define U 10000
#define N 1000012
#define INF 0x3f3f3f3f
#define MAX_READ 33554432
using namespace std;
inline int max(int x,int y){return (x>y)?x:y;}
char buf[MAX_READ],*l=buf;
inline int read()
{
int X=0;char ch=0;while('0'>ch||ch>'9')ch=*(l++);
while('0'<=ch&&ch<='9')X=(X<<3)+(X<<1)+(ch^48),ch=*(l++);return X;
}
char CH[12000012],nu[U][4],fnu[U][4];int cn=0,le[U];
inline void wr(int x){if(x<10000){memcpy(CH+cn,nu[x],le[x]);cn+=le[x];return;}int v=x/10000;wr(v);x-=v*10000;memcpy(CH+cn,fnu[x],4);cn+=4;}
#define ls p<<1
#define rs p<<1|1
using namespace std;
const int MAXN=1e6+5;
int n;
int q;
int x,y;
int op;
int Ne[MAXN];
int Hea[MAXN];
int Val[MAXN];
int A[MAXN];
int Nex[MAXN];
int Head[MAXN];
int Ans[MAXN];
struct Seg{
int ms;
int mx;
int l,r;
int add;
int lazy;
}Tree[MAXN*4];
inline void push_up(int p)
{
if(Tree[ls].mx==Tree[rs].mx)
{
Tree[p].mx=Tree[ls].mx;
Tree[p].ms=max(Tree[ls].ms,Tree[rs].ms);
}
else if(Tree[ls].mx>Tree[rs].mx)
{
Tree[p].mx=Tree[ls].mx;
Tree[p].ms=max(Tree[ls].ms,Tree[rs].mx);
}
else
{
Tree[p].mx=Tree[rs].mx;
Tree[p].ms=max(Tree[rs].ms,Tree[ls].mx);
}
}
inline void push_down(int p)
{
if(Tree[p].add)
{
int Mxc=max(Tree[ls].mx,Tree[rs].mx);
if(Tree[ls].mx==Mxc)
{
Tree[ls].mx=Tree[p].lazy;
Tree[ls].lazy=Tree[p].lazy;
Tree[ls].add+=Tree[p].add;
}
if(Tree[rs].mx==Mxc)
{
Tree[rs].mx=Tree[p].lazy;
Tree[rs].lazy=Tree[p].lazy;
Tree[rs].add+=Tree[p].add;
}
Tree[p].add=0;
Tree[p].lazy=0;
}
}
inline void Build(int p,int l,int r)
{
Tree[p].l=l;
Tree[p].r=r;
Tree[p].add=0;
Tree[p].mx=0x3f3f3f3f;
Tree[p].ms=0;
if(l==r)
{
return;
}
int mid=(l+r)>>1;
Build(ls,l,mid);
Build(rs,mid+1,r);
}
inline void Update(int p,int l,int r,int k)
{
if(l>r)
{
return;
}
if(Tree[p].mx<=k)
{
return;
}
if(Tree[p].l==Tree[p].r)
{
if(k<Tree[p].mx)
{
Tree[p].mx=k;
Tree[p].add++;
}
return;
}
if(Tree[p].l>=l&&Tree[p].r<=r)
{
if(Tree[p].mx<=k)
{
return;
}
else if(k>Tree[p].ms)
{
Tree[p].mx=k;
Tree[p].lazy=k;
Tree[p].add++;
return;
}
}
push_down(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
if(l<=mid)
{
Update(ls,l,r,k);
}
if(r>mid)
{
Update(rs,l,r,k);
}
push_up(p);
}
inline int Query(int p,int x)
{
if(Tree[p].l==Tree[p].r)
{
return Tree[p].add;
}
push_down(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
if(x<=mid)
{
return Query(ls,x);
}
else
{
return Query(rs,x);
}
}
inline void PreGet(){int i,x;for(i=0;i<U;i++){for(x=i;x;x/=10)nu[i][le[i]++]=(x%10)^48;memcpy(fnu[i],nu[i],4);for(x=le[i];x<=3;++x)fnu[i][x]=48;reverse(nu[i],nu[i]+le[i]);reverse(fnu[i],fnu[i]+4);}nu[0][0]=48;le[0]=1;}
int main()
{
PreGet();fread(buf,1,MAX_READ,stdin);
n=read();
q=read();
for(int i=1;i<=n;i++)
{
x=read();
A[i]=x;
Hea[i]=q+1;
Ne[q+1]=0;
}
for(int i=1;i<=q;i++)
{
op=read();
if(op==1)
{
x=read();
y=read();
Val[i]=y;
Ne[i]=Hea[x];
Hea[x]=i;
}
else
{
x=read();
Nex[i]=Head[x];
Head[x]=i;
}
}
Build(1,1,q);
for(int i=n;i>=1;i--)
{
int Lap=q;
for(int j=Hea[i];j;j=Ne[j])
{
int L=j;
int Rx=Lap;
if(j!=(q+1))
{
Update(1,max(L,1),Rx,Val[j]);
}
else
{
Update(1,1,Rx,A[i]);
}
Lap=j-1;
}
for(int j=Head[i];j;j=Nex[j])
{
Ans[j]=Query(1,j);
}
}
for(int i=1;i<=q;i++)
{
if(Ans[i])
{
wr(Ans[i]),CH[cn++]='\n';
}
}
fwrite(CH,1,cn,stdout);
}
标签:lazy,rs,int,练习,Tree,long,Ori,数据结构
From: https://www.cnblogs.com/kid-magic/p/17527281.html