## AtCoder ABC 342 G - Retroactive Range Chmax [<<回主頁](https://hackmd.io/@r1cky/Sk2hKzga6) ### 解題想法 我們可以開一棵線段樹來維護區間,區間操作單點查詢,然後取消操作的話,我們可以把線段樹的節點改成一個 pq,這樣每次查詢我們從 pq 裡面拿最大的值出來,如果發現他是被移除的就繼續從 pq 拿,做一次操作的上界是 $O(logN)$ (以下假設 $N=Q$),然後線段樹一次最多動到 $O(logN)$ 的節點,所以加入操作是 $O(log^2N)$,刪除的話用陣列維護可以弄到 $O(1)$ (實際的刪除會被挪動到查詢的時候)。 注意一次從 pq 整體拿出東西,有可能一次拿需要拿很多,但整體會均攤,不會超過 $O(Nlog^2N)$。 總時間複雜度 $O(Nlog^2N)$,但實際上不會那麼大,不會跑滿。 ### Code Java = ```Java= import java.util.*; import java.time.*; import java.io.*; import java.math.*; public class Main{ public static BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); public static BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out)); public static long ret,cnt,ansl; public static int reti,rd,n,m,ans; public static String[] in; public static String in1=""; public static boolean neg,b1,b2,b3; public static final int mod=998244353,mox=998244352,mod2=1_000_000_007,ma=200015; public static Useful us=new Useful(mod2); public static int[] A=new int[ma]; public static int[] B=new int[ma]; public static int[] C=new int[ma]; public static int[] D=new int[ma]; public static long[] Al=new long[ma]; public static long[] Bl=new long[ma]; public static ArrayList<ArrayList<Integer>> E=new ArrayList<>(); public static ArrayList<ArrayList<Integer>> E=new ArrayList<>(); public static void main(String[] args) throws Exception{ final int n=readint(); int op,l,r,x; Node tree=build(1,n); for(int i=1;i<=n;i++) { A[i]=readint(); } final int q=readint(); boolean[] rm=new boolean[ma]; for(int i=1;i<=q;i++) { op=readint(); if(op==1) { l=readint(); r=readint(); x=readint(); add(tree,1,n,l,r,i,x); } if(op==2) { x=readint(); rm[x]=true; } if(op==3) { x=readint(); bw.write(Math.max(A[x], query(tree,rm,1,n,x))+"\n"); } } bw.flush(); } public static Node build(int l,int r) { Node now=new Node(); if(l!=r) { int mid=(l+r)>>1; now.l=build(l,mid); now.r=build(mid+1,r); } return now; } public static void add(Node x,int l,int r,int ql,int qr,int op,int v) { if(r<ql||l>qr) { return; } if(ql<=l&&r<=qr) { x.modify(op,v); return; } int mid=(l+r)>>1; add(x.l,l,mid,ql,qr,op,v); add(x.r,mid+1,r,ql,qr,op,v); } public static int query(Node x,boolean[] rm,int l,int r,int q) { if(l==r)return x.get(rm); int mid=(l+r)>>1; if(q<=mid) { return Math.max(x.get(rm), query(x.l,rm,l,mid,q)); } return Math.max(x.get(rm), query(x.r,rm,mid+1,r,q)); } /* */ //fast io public static int readint() throws Exception{ reti=0; neg=false; while(rd<48||rd>57) { rd=br.read(); if(rd=='-') { neg=true; } // if(rd<0) { // return -1; //EOF // } } while(rd>47&&rd<58) { reti*=10; reti+=(rd&15); rd=br.read(); } if(neg)reti*=-1; return reti; } public static long readlong() throws Exception{ ret=0; neg=false; while(rd<48||rd>57) { rd=br.read(); if(rd=='-') { neg=true; } } while(rd>47&&rd<58) { ret*=10; ret+=(rd&15); rd=br.read(); } if(neg)ret*=-1; return ret; } //fast typing public static int pint(String in) { return Integer.parseInt(in); } public static long plong(String in) { return Long.parseLong(in); } public static void outn() { System.out.println(); } public static void outn(char in) { System.out.println(in); } public static void outn(long in) { System.out.println(in); } public static void outn(double in) { System.out.println(in); } public static void outn(boolean in) { System.out.println(in); } public static void outn(String in) { System.out.println(in); } public static void outn(Object in) { System.out.println(in); } public static void out(char in) { System.out.print(in); } public static void out(long in) { System.out.print(in); } public static void out(double in) { System.out.print(in); } public static void out(boolean in) { System.out.print(in); } public static void out(String in) { System.out.print(in); } public static void out(Object in) { System.out.print(in); } public static void fl() { System.out.flush(); } public static String[] res() throws IOException{ return br.readLine().split(" "); } public static String re() throws IOException{ return br.readLine().split(" ")[0]; } } /* */ /* */ class Node { Node l, r; Pii u; PriorityQueue<Pii> pq=new PriorityQueue<>(new Comparator<Pii>() { public int compare(Pii f,Pii s) { return s.y-f.y; } }); Node(){ } int get(boolean[] rm) { while(!pq.isEmpty()) { u=pq.poll(); if(!rm[u.x]) { pq.offer(u); return u.y; } } return 0; } void modify(int op,int v) { pq.offer(new Pii(op,v)); } } class ooo{ int x,y,z; public String err() { return x+" "+y+" "+z; } ooo(int x1,int y1,int z1){ x=x1; y=y1; z=z1; } } class Pii{ int x,y; Pii(int a,int b){ x=a; y=b; } public String err() { return x+" "+y; } @Override public boolean equals(Object o) { if (this==o) return true; if (!(o instanceof Pii)) return false; Pii key = (Pii) o; return x==key.x&&y==key.y; } @Override public int hashCode() { long result=x; result=31*result+y; return (int)(result%998244353); } } class Pll{ long x,y; Pll(long a,long b){ x=a; y=b; } public String err() { return x+" "+y; } @Override public boolean equals(Object o) { if (this==o) return true; if (!(o instanceof Pll)) return false; Pll key = (Pll) o; return x==key.x&&y==key.y; } @Override public int hashCode() { long result=x; result=31*result+y; return (int)(result%998244353); } } class Useful{ long mod; Useful(long m){mod=m;} void al(ArrayList<ArrayList<Integer>> a,int n){for(int i=0;i<n;i++) {a.add(new ArrayList<Integer>());}} void arr(int[] a,int init) {for(int i=0;i<a.length;i++) {a[i]=init;}} void arr(long[] a,long init) {for(int i=0;i<a.length;i++) {a[i]=init;}} void arr(int[][] a,int init) {for(int i=0;i<a.length;i++) {for(int j=0;j<a[i].length;j++) {a[i][j]=init;}}} void arr(long[][] a,long init) {for(int i=0;i<a.length;i++) {for(int j=0;j<a[i].length;j++) {a[i][j]=init;}}} void arr(int[][][] a,int init) {for(int i=0;i<a.length;i++) {for(int j=0;j<a[i].length;j++) {for(int k=0;k<a[i][j].length;k++) {a[i][j][k]=init;}}}} void arr(long[][][] a,long init) {for(int i=0;i<a.length;i++) {for(int j=0;j<a[i].length;j++) {for(int k=0;k<a[i][j].length;k++) {a[i][j][k]=init;}}}} void arr(int[][][][] a,int init) {for(int i=0;i<a.length;i++) {for(int j=0;j<a[i].length;j++) {for(int k=0;k<a[i][j].length;k++) {Arrays.fill(a[i][j][k],init);}}}} void arr(long[][][][] a,long init) {for(int i=0;i<a.length;i++) {for(int j=0;j<a[i].length;j++) {for(int k=0;k<a[i][j].length;k++) {Arrays.fill(a[i][j][k],init);}}}} long fastn(long x,long pw) { if(pw==1)return x; long h=fastn(x,pw>>1); if((pw&1)==0) { return h*h; } return h*h*x; } long fast(long x,long pw) { if(x==0)return 1; if(pw<=0)return 1; if(pw==1)return x; long h=fast(x,pw>>1); if((pw&1)==0) { return h*h%mod; } return h*h%mod*x%mod; } long fast(long x,long pw,long mod) { if(pw<=0)return 1; if(pw==1)return x; long h=fast(x,pw>>1,mod); if((pw&1)==0) { return h*h%mod; } return h*h%mod*x%mod; } long[][] mul(long[][] a,long[][] b){ long[][] c=new long[a.length][b[0].length]; for(int i=0;i<a.length;i++) { for(int j=0;j<b[0].length;j++) { for(int k=0;k<a[0].length;k++) { c[i][j]+=a[i][k]*b[k][j]; c[i][j]%=mod; } } } return c; } long[][] mul(long[][] a,long[][] b,long mod){ long[][] c=new long[a.length][b[0].length]; for(int i=0;i<a.length;i++) { for(int j=0;j<b[0].length;j++) { for(int k=0;k<a[0].length;k++) { c[i][j]+=a[i][k]*b[k][j]; c[i][j]%=mod; } } } return c; } long[][] fast(long[][] x,long pw){ if(pw==1)return x; long[][] h=fast(x,pw>>1); if((pw&1)==0) { return mul(h,h); } else { return mul(mul(h,h),x); } } long[][] fast(long[][] x,long pw,long mod){ if(pw==1)return x; long[][] h=fast(x,pw>>1,mod); if((pw&1)==0) { return mul(h,h,mod); } else { return mul(mul(h,h,mod),x,mod); } } int gcd(int a,int b) { if(a==0)return b; if(b==0)return a; return gcd(b,a%b); } long gcd(long a,long b) { if(a==0)return b; if(b==0)return a; return gcd(b,a%b); } long lcm(long a, long b){ return a*(b/gcd(a,b)); } double log2(long x) { return (Math.log(x)/Math.log(2)); } double logx(long x,long y) { return (Math.log(y)/Math.log(x)); } } ```