Problem:
Multi-Set

For a set $S$ of integers, perform a sequence of the following operations. Note that multiple elements can have equivalent values in $S$.

insert($x$): Insert $x$ to $S$ and report the number of elements in $S$ after the operation.

find($x$): Report the number of $x$ in $S$.

delete($x$): Delete all $x$ from $S$.

dump($L$, $R$): Print elements $x$ in $S$ such that $L \leq x \leq R$.

Input

The input is given in the following format.

$q$
$query_1$
$query_2$
:
$query_q$

Each query $query_i$ is given by

0 $x$

or

1 $x$

or

2 $x$

or

3 $L$ $R$

where the first digits 0, 1, 2 and 3 represent insert, find, delete and dump operations respectively.

Output

For each insert operation, print the number of elements in $S$.

For each find operation, print the number of specified elements in $S$.

For each dump operation, print the corresponding elements in ascending order. Print an element in a line.

Constraints

$1 \leq q \leq 200,000$

$0 \leq x \leq 1,000,000,000$

The total number of elements printed by dump operations does not exceed $1,000,000$

The sum of numbers printed by find operations does not exceed $2,000,000$

Sample Input 1

10
0 1
0 1
0 2
0 3
2 2
1 1
1 2
1 3
0 4
3 1 4

Sample Output 1

1
2
3
4
2
0
1
4
1
1
3
4

Solution in JAVA (judge verdict: Runtime Error)

import java.io.*;
import java.util.*;

public class Main {

    public static void main(String[] args) {
        Scanner in=new Scanner (System.in);
        PrintWriter out=new PrintWriter(System.out);
        myMultiSet mset=new myMultiSet();
        int q=Integer.parseInt(in.next());
        for(int i=0;i<q;i++) {
            int odr=Integer.parseInt(in.next());
            
            switch(odr) {
            case 0:
            	int x0=Integer.parseInt(in.next());
            	mset.insert(x0);
            	System.out.println(mset.size());
            	break;
            	
            case 1:
            	int x1=Integer.parseInt(in.next());
            	System.out.println(mset.find(x1));
            	break;
            	
            case 2:
            	int x2=Integer.parseInt(in.next());
            	mset.deleteOf(x2);
            	break;
            	
            case 3:
            	int L=Integer.parseInt(in.next()),R=Integer.parseInt(in.next());
            	mset.dump(L, R);
            	break;
            }
        }
    }

}

class Bnode{
    int v,num;
    Bnode p,l,r;

    Bnode(int v,int num){
        this.v=v;
        this.num=num;
    }
}

class myMultiSet{
	PrintWriter out=new PrintWriter(System.out);
	Bnode NOW,END,ROOT;
	int size,fact;
	
	myMultiSet(){
		END=new Bnode(-1,-1);
		END.p=END;
		END.l=END;
		END.r=END;
		init();
		size=0;
		fact=0;
	}
	private void init() {
		ROOT=END;
	}
	
	void insert(int x) {
		Bnode NEW=new Bnode(x,1);
		NEW.l=END;
		NEW.r=END;
		if(size==0) {
			ROOT=NEW;
		}
		else {
			NOW=ROOT;
			while(true) {
				if(NEW.v==NOW.v) {
					NOW.num++;
					break;
				}
				else if(NEW.v<NOW.v) {
					if(NOW.l==END) {
						NOW.l=NEW;
						NEW.p=NOW;
						break;
					}
					else NOW=NOW.l;
				}
				else {
					if(NOW.r==END) {
						NOW.r=NEW;
						NEW.p=NOW;
						break;
					}
					else NOW=NOW.r;
				}
			}
		}
		size++;
		fact++;
	}
	
	int size() {
		return size;
	}
	
	private Bnode search(int x) {
		NOW=ROOT;
		while(true) {
			//System.out.println("SEARCHING:"+NOW.v);
			if(x==NOW.v)break;
			else if((x<NOW.v && NOW.l.v==-1) || (x>NOW.v && NOW.r.v==-1))break;
			else if(x<NOW.v)NOW=NOW.l;
			else NOW=NOW.r;
		}
		return NOW;
	}
	
	int find(int x) {
		Bnode F=search(x);
		return (F.v==x)? F.num : 0;
	}
	
	void deleteOf(int x) {
		Bnode T=search(x);
		//System.out.println("x="+x+"T.v="+T.v);
		if(T.v==x) {
			size-=T.num;
			fact--;
			delete(T);
		}
	}
	
	private void delete(Bnode Del) {
		if(Del.l!=END && Del.r!=END) deleteHaveChilds(Del);
		else if(Del.l!=END || Del.r!=END) deleteHaveaChild(Del);
		else if(Del.l==END && Del.r==END) deleteNoChild(Del);
		else System.out.println("ERR");
	}
	
	private void deleteNoChild(Bnode D) {
		//System.out.printf("D.v=%d D.p.v=%d",D.v,D.p.v);
		if(fact==1)init();
		else if(D.p.l==D)D.p.l=END;
		else D.p.r=END;
	}
	
	private void deleteHaveaChild(Bnode D) {
		Bnode child;
		if(D.l!=END)child=D.l;
		else child=D.r;
		
		if(D==ROOT)ROOT=child;
		else if(D.p.l==D)D.p.l=child;
		else D.p.r=child;
		
		child.p=D.p;
	}
	
	private void deleteHaveChilds(Bnode D) {
		Bnode Sub=findNextNodeToDelete(D);
		D.v=Sub.v;
		D.num=Sub.num;
		delete(Sub);
	}
	
	private Bnode findNextNodeToDelete(Bnode N) {
		if(N.l!=END) return findNextNodeToDelete(N.l);
		else return N;
	}
	
	void dump(int L,int R) {
		NOW=ROOT;
		inodrwalk(NOW,L,R);
		out.flush();
	}
	
	private void inodrwalk(Bnode N,int L,int R) {
		if(N.l!=END)inodrwalk(N.l,L,R);
		if(N.v>=L && N.v<=R) {
			for(int j=0;j<N.num;j++)out.println(N.v);
		}
		if(N.r!=END)inodrwalk(N.r,L,R);
	}
	
}