codeforces Goodbye 2014 E题(线段树,二分)

2015-01-01 01:18:46

思路:这道题补了好久....分析了许多代码。虽然实现方法很多,但核心思想是一样的。

  首先,考虑直接暴力维护复杂度O(n*n),必T。我们需要一种近线性的方法,也就是只要“扫一遍”的那种算法,那么很自然地想到要离线处理询问。

  然户考虑方向,如果按询问的xi升序并从头开始扫,貌似不容易想.....,深入思考,每个多米诺骨牌倒下后只会影响后面,而不影响前面,所以我们逆序处理,从最后一个骨牌开始,这样一来我们就要优先处理xi比较大的询问了。那么将所有询问按xi降序排列。

  对于每个骨牌k,我们处理xi==k的询问。若它倒下,那么它前面若干个(可能为0)也会倒下,直到碰不到某个骨牌,那么我们可以把这个骨牌的影响一个区间,区间内的骨牌都能能随着它倒下而倒下,每个骨牌代价为0,而区间右边的那个骨牌是骨牌k碰不到的第一个骨牌(设为q),它的代价就为W = L(q) - L(k),意思就是如果询问为[k,q],那么代价是W。(这种定义方式方便了查询,如果询问是[k,q - 1],那么代价是0)那么我们就定义询问的代价就是区间内代价和。这样线段树就派上用场了。(对于骨牌影响区间的置0可以用区间更新,第一个碰不到的骨牌的代价用单点更新。)

  具体看代码吧...有很多细节的。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <vector>
  6 #include <map>
  7 #include <set>
  8 #include <stack>
  9 #include <queue>
 10 #include <iostream>
 11 #include <algorithm>
 12 using namespace std;
 13 #define lp (p << 1)
 14 #define rp (p << 1|1)
 15 #define getmid(l,r) (l + (r - l) / 2)
 16 #define MP(a,b) make_pair(a,b)
 17 typedef long long ll;
 18 typedef unsigned long long ull;
 19 typedef pair<int,int> pii;
 20 const int INF = 1e9;
 21 const int maxn = 300010;
 22 
 23 int n,m;
 24 int x[maxn],len[maxn],ans[maxn];
 25 struct query{
 26     int x,y,id;
 27     bool operator < (const query &b) const{
 28         return x > b.x;
 29     }
 30 }q[maxn];
 31 
 32 struct SegTree{
 33     int t[maxn << 2],cover[maxn << 2];
 34     void Build(int p,int l,int r){
 35         t[p] = INF;
 36         cover[p] = 0;
 37         if(l == r) return;
 38         int mid = getmid(l,r);
 39         Build(lp,l,mid);
 40         Build(rp,mid + 1,r);
 41     }
 42     void Push_down(int p){
 43         if(cover[p]){
 44             cover[lp] = cover[rp] = 1;
 45             t[lp] = t[rp] = 0;
 46             cover[p] = 0;
 47         }
 48     }
 49     void Update_interval(int a,int b,int p,int l,int r){
 50         if(a <= l && r <= b){
 51             t[p] = 0;
 52             cover[p] = 1;
 53             return;
 54         }
 55         Push_down(p);
 56         int mid = getmid(l,r);
 57         if(a <= mid) Update_interval(a,b,lp,l,mid);
 58         if(b > mid) Update_interval(a,b,rp,mid + 1,r);
 59         t[p] = t[lp] + t[rp];
 60     }
 61     void Update_point(int a,int c,int p,int l,int r){
 62         if(l == r){
 63             t[p] = min(t[p],c);
 64             return;
 65         }
 66         Push_down(p);
 67         int mid = getmid(l,r);
 68         if(a <= mid) Update_point(a,c,lp,l,mid);
 69         else Update_point(a,c,rp,mid + 1,r);
 70         t[p] = t[lp] + t[rp];
 71     }
 72     int Query(int a,int b,int p,int l,int r){
 73         if(a <= l && r <= b){
 74             return t[p];
 75         }
 76         Push_down(p);
 77         int mid = getmid(l,r),res = 0;
 78         if(a <= mid) res += Query(a,b,lp,l,mid);
 79         if(b > mid) res += Query(a,b,rp,mid + 1,r);
 80         t[p] = t[lp] + t[rp];
 81         return res;
 82     }
 83 }T;
 84 
 85 int main(){
 86     int a,b;
 87     scanf("%d",&n);
 88     T.Build(1,1,n);
 89     for(int i = 1; i <= n; ++i){
 90         scanf("%d%d",&x[i],&len[i]);
 91     }
 92     scanf("%d",&m);
 93     for(int i = 1; i <= m; ++i){
 94         scanf("%d%d",&q[i].x,&q[i].y);
 95         q[i].id = i;
 96     }
 97     sort(q + 1,q + m + 1);
 98     int cur = 1;
 99     for(int i = n - 1; i >= 1; --i){
100         int pos = lower_bound(x + 1,x + n + 1,x[i] + len[i]) - x;
101         if(pos - 1 >= i + 1) T.Update_interval(i + 1,pos - 1,1,1,n);
102         if(pos <= n) T.Update_point(pos,x[pos] - x[i] - len[i],1,1,n);
103         while(cur <= m && q[cur].x == i){
104             ans[q[cur].id] = T.Query(q[cur].x + 1,q[cur].y,1,1,n);
105             cur++;
106         }
107     }
108     for(int i = 1; i <= m; ++i) printf("%d\n",ans[i]);
109     return 0;
110 }

 

posted @ 2015-01-01 01:34  Naturain  阅读(321)  评论(0编辑  收藏  举报