51nod 差和问题(树状数组+离散化 (Java))


题目链接:

http://www.51nod.com/contest/problem.html#!problemId=1394


题目描述:

有一个集合S,初始状态下有n个元素,对他进行如下操作:

1、向S里面添加一个值为v的元素。输入格式为1 v

2、向S里面删除一个值为v的元素。输入格式为2 v

3、询问S里面的元素两两之差绝对值之和。输入格式为3

 

对于样例,

操作3,|1-2|+|1-3|+|2-3|=4

操作1 4之后,集合中的数字为1 2 3 4

操作3,|1-2|+|1-3|+|2-3|+|1-4|+|2-4|+|3-4|=10

操作2 2之后,集合中的数字为1 3 4

操作3,|1-3|+|1-4|+|3-4|=6


Input
第一行输入两个整数n,Q表示集合中初始元素个数和操作次数。(1<=n,Q<=100,000)
第二行给出n个整数a[0],a[1],a[2],…,a[n-1],表示初始集合中的元素。(0<=a[i]<=1,000,000,000) 
接下来Q行,每行一个操作。(0<=v<=1,000,000,000)
Output
对于第2类操作,如果集合中不存在值为v的元素可供删除,输出-1。
对于第3类操作,输出答案。
Input示例
3 5
1 2 3
3
1 4
3
2 2
3
Output示例
4
10
6


大致思路:把所有操作离线,把涉及到的数离散化,然后用树状数组维护比此数小的所有数的和,比此数小的所有数的个数,就能Ologn 询问出操作3了。

离散化用了Java的hashmap


代码:

import java.util.HashMap;
import java.util.Map;
import java.math.*;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.IOException;  
import java.io.InputStream;  
import java.io.InputStreamReader;  
import java.math.BigInteger;  
import java.util.StringTokenizer;  
import java.io.PrintWriter;
import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        Scanner in = new Scanner(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }
    static int tp = 0;
    static class TaskE {
    	
    	static int n, Q;
        public void solve(int testNumber, Scanner in, PrintWriter out) {
        	n = in.nextInt();
        	Q = in.nextInt();
        	Map<Integer, Integer> mp = new HashMap<Integer, Integer>();
        	int num[] = new int[n + 10];
        	int cnt[] = new int[n + Q + 10];
        	int all[] = new int[n + Q + 10];
        	int vs[] = new int[n + Q + 10];
        	int top = 0;
        	for(int i = 0; i < n; i ++) {
        		num[i] = in.nextInt();
        		all[top ++] = num[i];
        	}
        	pii qry[] = new pii[Q];
        	for(int i = 0; i < Q; i ++) qry[i] = new pii(0, 0);
        	for(int i = 0; i < Q; i ++) {
        		qry[i].X = in.nextInt();
        		if(qry[i].X == 3) continue;
        		qry[i].Y = in.nextInt();
        		all[top ++] = qry[i].Y;	
        	}
        	Arrays.sort(all, 0, top);;
        	for(int i = 0; i < top; i ++) {
        		int it = all[i];
        		if(mp.containsKey(it)) continue;
        		mp.put(it, ++tp);
        		vs[tp] = it;
        	}
        	BIT A = new BIT();
        	BIT B = new BIT();
        	long sumval = 0, cur = 0, sumc = 0;
        	for(int i = 0; i < n; i ++ ) {
        		int val = num[i];
        		int id = mp.get(val);
        		long sufval = A.query(id);
        		long sufcnt = B.query(id);
        		cur += sufcnt * val - sufval;
        		cur += (sumval - sufval) - (sumc - sufcnt) * val;
        		sumval += val;
        		sumc ++;
        		A.update(id, val);
        		B.update(id, 1);
        		cnt[id] ++;
        	}
        	for(int i = 0; i < Q; i ++) {
        		int op = qry[i].X;
        		if(op == 3) {
        			out.println(cur);
        			out.flush();
        		} else if(op == 1) {
        			int val = qry[i].Y;
        			int id = mp.get(val);
            		long sufval = A.query(id);
            		long sufcnt = B.query(id);
            		cur += sufcnt * val - sufval;
            		cur += (sumval - sufval) - (sumc - sufcnt) * val;
            		sumval += val;
            		sumc ++;
            		A.update(id, val);
            		B.update(id, 1);
            		cnt[id] ++;
        		} else if(op == 2) {
        			int val = qry[i].Y;
        			int id = mp.get(val);
        			if(cnt[id] == 0) {
        				out.println("-1");
        				out.flush();
        				continue;
        			}
        			long sufval = A.query(id);
        			long sufcnt = B.query(id);
            		cur -= sufcnt * val - sufval;
            		cur -= (sumval - sufval) - (sumc - sufcnt) * val;
            		sumval -= val;
            		sumc --;
            		A.update(id, -val);
            		B.update(id, -1);
            		cnt[id] --;
        		}
        	}
        	
        }
    }
    static class BIT {
    	long sum[] = new long[tp + 100];
    	int lowbit(int x) {
    		return x & -x;
    	}
    	public void update(int id,long val) {
    		for(int i = id; i <= tp ; i += lowbit(i)) sum[i] += val;
    	}
    	public long query(int id) {
    		long ans = 0;
    		for(int i = id; i != 0; i -= lowbit(i)) 
    			ans += sum[i];
    		return ans;
    	}
    }

    static class pii implements Comparable<pii> {
		int X, Y;
		pii(int X, int Y) {
			this.X = X;
			this.Y = Y;
		}
		public int compareTo(pii a) {
			if(this.X - a.X != 0) return this.X - a.X;
			else return this.Y - a.Y;
		}
	}
    static class Scanner {  
		BufferedReader br;  
		StringTokenizer st;  
			  
		public Scanner(InputStream in) {
			br = new BufferedReader(new InputStreamReader(in));
			eat("");
		} 
		
		private void eat(String s) {  
			st = new StringTokenizer(s);
		}  
	  
		public String nextLine() {  
			try {  
				return br.readLine();  
			} catch (IOException e) {  
				return null;  
			}  
		}  
	  
		public boolean hasNext() {  
			while (!st.hasMoreTokens()) {  
				String s = nextLine();  
				if (s == null)  
				return false;  
				eat(s);  
			}  
			return true;  
		}  
	  
		public String next() {  
			hasNext();  
			return st.nextToken();  
		}  
	  
		public int nextInt() {  
			return Integer.parseInt(next());  
		}  
		  
		public long nextLong() {  
			return Long.parseLong(next());  
		}  
			  
		public double nextDouble() {  
			return Double.parseDouble(next());  
		}  
		  
		public BigInteger nextBigInteger() {  
			return new BigInteger(next());  
		}  
		  
		public int[] nextIntArray(int n) {  
			int[] is = new int[n];  
			for (int i = 0; i < n; i++) {  
				is[i] = nextInt();  
			}  
			return is;  
		}  
	  
		public long[] nextLongArray(int n) {  
			long[] ls = new long[n];  
			for (int i = 0; i < n; i++) {  
				ls[i] = nextLong();  
			}  
			return ls;  
		}  
		 
		public double[] nextDoubleArray(int n) {  
			double[] ds = new double[n];  
			for (int i = 0; i < n; i++) {  
				ds[i] = nextDouble();  
			}  
			return ds;  
		}  
	  
		public BigInteger[] nextBigIntegerArray(int n) {  
			BigInteger[] bs = new BigInteger[n];  
			for (int i = 0; i < n; i++) {  
				bs[i] = nextBigInteger();  
			}  
			return bs;  
		}  
	  
		public int[][] nextIntMatrix(int row, int col) {  
			int[][] mat = new int[row][];  
			for (int i = 0; i < row; i++) {  
				mat[i] = nextIntArray(col);  
			}  
			return mat;  
		}  
	  
		public long[][] nextLongMatrix(int row, int col) {  
			long[][] mat = new long[row][];  
			for (int i = 0; i < row; i++) {  
				mat[i] = nextLongArray(col);  
			}  
			return mat;  
		}  
	  
		public double[][] nextDoubleMatrix(int row, int col) {  
			double[][] mat = new double[row][];  
			for (int i = 0; i < row; i++) {  
				mat[i] = nextDoubleArray(col);  
			}  
			return mat;  
		}  
	  
		public BigInteger[][] nextBigIntegerMatrix(int row, int col) {  
			BigInteger[][] mat = new BigInteger[row][];  
			for (int i = 0; i < row; i++) {  
				mat[i] = nextBigIntegerArray(col);  
			}  
			return mat;  
		}  
    }  
}  




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值