Trace 2018徐州icpc网络赛 (二分)(树状数组)

 

There's a beach in the first quadrant. And from time to time, there are sea waves. A wave ( xxx , yyy ) means the wave is a rectangle whose vertexes are ( 000 , 000 ), ( xxx , 000 ), ( 000 , yyy ), ( xxx , yyy ). Every time the wave will wash out the trace of former wave in its range and remain its own trace of ( xxx , 000 ) -> ( xxx , yyy ) and ( 000 , yyy ) -> ( xxx , yyy ). Now the toad on the coast wants to know the total length of trace on the coast after n waves. It's guaranteed that a wave will not cover the other completely.

Input

The first line is the number of waves n(n≤50000)n(n \le 50000)n(n50000).

The next nnn lines,each contains two numbers xxx yyy ,( 0<x0 < x0<x , y≤10000000y \le 10000000y10000000 ),the iii-th line means the iii-th second there comes a wave of ( xxx , yyy ), it's guaranteed that when 1≤i1 \le i1i , j≤nj \le njn ,xi≤xjx_i \le x_jxixj and yi≤yjy_i \le y_jyiyj don't set up at the same time.

Output

An Integer stands for the answer.

Hint:

As for the sample input, the answer is 3+3+1+1+1+1=103+3+1+1+1+1=103+3+1+1+1+1=10

样例输入

3
1 4
4 1
3 3

样例输出

10

题目来源

ACM-ICPC 2018 徐州赛区网络预赛

 

比赛的时候想的是手撸一个平衡树排序,然后二分查找这个点左右两边的点,再比较他们的边值,结果数据结构写炸了

赛后看到网上题解才想起set和list 这些stl 太弱了Orz 

用set这类的话 就把一个点的边值拆成两个处理,从后往前,(后面的点总是覆盖前面),看看当今的点时候比后面的点边值高出多少

set的二分还是要%一下,毕竟没这么写过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long ll;
 5 int n;
 6 const int maxn = 5e4+5;
 7 const int maxnn = 1e7+7;
 8 
 9 vector<int>vec1,vec2;
10 ll solve(vector<int>vec)
11 {
12     ll ans = 0;
13     int sz = vec.size();
14     set<int>st;
15     for(int i=n-1;i>=0;i--)
16     {
17         set<int>::iterator it = st.lower_bound(vec[i]);
18         if(it == st.begin())ans += vec[i];
19         else
20         {
21             it--;
22             ans += vec[i] - *it;
23         }
24         st.insert(vec[i]);
25     }
26     return ans;
27 }
28 
29 int main()
30 {
31     scanf("%d",&n);
32     int x,y;
33     for(int i=1;i<=n;i++)
34     {
35      scanf("%d%d",&x,&y);
36      vec1.push_back(x);
37      vec2.push_back(y);
38     }
39     printf("%lld\n",solve(vec1)+solve(vec2));
40 }
View Code

 

 除了可以二分之外 还有树状数组的写法,能树状数组肯定可以线段树。这里先补上树状数组的做法。

trex表示是一个记录相应x位置的y的值的前缀和,trey也类似

  那么插入(4,1)的时候 更改trex,trey, y from 0 到 1 所遇到的横向遇到x都是3;x from 0 to 3 和 from 4 to 4 对应y值不同,这样就用到树状数组的区间更新

  把query 出来的上一个位置+1的位置更新加上现在的点和之前的差值 然后在现在位置+1的位置减去  例如:trex(x在各个位置对应的y值) 3+1位置加上差值 (1-3) 4+1位置加上差值的相反数

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 5e4+5;
 5 const int maxx = 1e7+5;
 6 int n;
 7 struct Node
 8 {
 9     int x,y;
10 }node[maxn];
11 int trex[maxx];
12 int trey[maxx];
13 
14 int maxxx = 0;
15 int lowbit(int x)
16 {
17     return x &(-x);
18 }
19 void add(int x,int val,int *tre)
20 {
21     for(int i=x;i<=maxxx;i+=lowbit(i))
22     {
23         tre[i] += val;
24     }
25 }
26 
27 int query(int x,int *tre)
28 {
29     int ans = 0;
30     for(int i=x;i>0;i-=lowbit(i))
31     {
32         ans += tre[i];
33     }
34     return ans;
35 }
36 int main()
37 {
38     scanf("%d",&n);
39     for(int i=1;i<=n;i++)
40     {
41         scanf("%d%d",&node[i].x,&node[i].y);
42         maxxx = max(maxxx,max(node[i].x,node[i].y));
43     }
44     ll ans = 0;
45     for(int i=n;i>0;i--)
46     {
47         int x = node[i].x;
48         int y = node[i].y;
49         int lenx = query(y,trey);
50         int leny = query(x,trex);
51         ans += x - lenx;
52         ans += y - leny;
53         int valy = query(x,trex);
54         int valx = query(y,trey);
55         add(valy+1,x-valx,trey);
56         add(y+1,valx-x,trey);
57         add(valx+1,y-valy,trex);
58         add(x+1,valy-y,trex);
59         //printf("%d---%d    %d---%d    %d----%d\n",x,y,x-valx,y-valy,valx,valy);
60     }
61     printf("%lld\n",ans);
62 }
View Code

 

 

posted @ 2018-09-09 22:12  进击的黑仔  阅读(385)  评论(0编辑  收藏  举报