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 }