题意:
要求动态求问是否有一个 1~n 的排列,使得满足 $p_i leq a_i$,给定 $a_i$ 初始值,接下来 m次单个位置修改,每次求问是否可以构造出来。
解法:
构造一序列使得 $cnt_i$ 表示 $a$ 序列当前 i 的个数,记 $suffix(i)$ 为此序列的后缀和。
那么可以构造出序列 <-> $ 0 leq suffix(i) - (n-i+1)$,建权值线段树维护 $suffix(i) - (n-i+1)$ 即可。
#include <bits/stdc++.h> #define l(x) ch[x][0] #define r(x) ch[x][1] #define LL long long const int N = 200010; using namespace std; int totn,n,a[N]; int ch[N<<1][2]; LL minv[N<<1],addv[N<<1]; void update(int x) { minv[x] = min(minv[l(x)], minv[r(x)]); } void push(int x) { if(addv[x]==0) return; addv[l(x)] += addv[x], minv[l(x)] += addv[x]; addv[r(x)] += addv[x], minv[r(x)] += addv[x]; addv[x] = 0; } int build(int l,int r) { int x = ++totn; addv[x] = 0; if(l==r) { l(x) = r(x) = 0; minv[x] = -l; return x; } int mid = (l+r)>>1; l(x) = build(l,mid); r(x) = build(mid+1,r); update(x); return x; } void add(int x,int l,int r,int ql,int qr,LL qv) { push(x); if(ql<=l && r<=qr) { addv[x] = qv; minv[x] += qv; return ; } int mid = (l+r)>>1; if(ql<=mid) add(l(x),l,mid,ql,qr,qv); if(mid<qr) add(r(x),mid+1,r,ql,qr,qv); update(x); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); a[i] = n-a[i]+1; } build(1,n); for(int i=1;i<=n;i++) add(1,1,n,a[i],n,1); int m; scanf("%d",&m); if(minv[1]>=0) puts("TAK"); else puts("NIE"); for(int i=1,x,v;i<=m;i++) { scanf("%d%d",&x,&v); v = n-v+1; add(1,1,n,a[x],n,-1); add(1,1,n,v,n,1); a[x] = v; if(minv[1]>=0) puts("TAK"); else puts("NIE"); } return 0; }