题目链接:
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
第一行输入两个整数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)
对于第2类操作,如果集合中不存在值为v的元素可供删除,输出-1。 对于第3类操作,输出答案。
3 5 1 2 3 3 1 4 3 2 2 3
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; } } }