1. 程式人生 > >HDU 4417.Super Mario-無修改區間小於等於H的數的個數-可持久化線段樹

HDU 4417.Super Mario-無修改區間小於等於H的數的個數-可持久化線段樹

url java ios else string mes clu ber lower

Super Mario

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 9618 Accepted Submission(s): 4074


Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble again and Mario needs to save his lover. We regard the road to the boss’s castle as a line (the length is n), on every integer point i there is a brick on height hi. Now the question is how many bricks in [L, R] Mario can hit if the maximal height he can jump is H.

Input The first line follows an integer T, the number of test data.
For each test data:
The first line contains two integers n, m (1 <= n <=10^5, 1 <= m <= 10^5), n is the length of the road, m is the number of queries.
Next line contains n integers, the height of each brick, the range is [0, 1000000000].
Next m lines, each line contains three integers L, R,H.( 0 <= L <= R < n 0 <= H <= 1000000000.)

Output For each case, output "Case X: " (X is the case number starting from 1) followed by m lines, each line contains an integer. The ith integer is the number of bricks Mario can hit for the ith query.

Sample Input 1 10 10 0 5 2 7 5 4 3 8 7 7 2 8 6 3 5 0 1 3 1 1 9 4 0 1 0 3 5 5 5 5 1 4 6 3 1 5 7 5 7 3

Sample Output Case 1: 4 0 0 3 1 2 0 1 5 1

Source 2012 ACM/ICPC Asia Regional Hangzhou Online 題意就是求區間小於等於H的數的個數。 這道題寫的時間有點長,錯在這幾個地方: (1)因為數是從0開始的,所以查詢的時候,區間l[i]和r[i]應該+1,查詢的時候就l[i]-1,r[i],或者區間l[i]和r[i]不變化,查詢的時候,就l[i],r[i]+1。 (2)因為查詢的是小於等於H的數,所以H也應該離散化,找對應的數,而不是直接查詢,這裏錯了好久才發現。 (3)數組開小了,杭電這道題數組開小了報的是WA,把maxn=1e5+10改成2e5+10就過了。 還有一點,其實是自己腦子不好特意測了一下。 因為數據已經離散化處理過了,所以查詢的時候不會有重復的數,所以查詢的時候,lower_bound()和upper_bound()都可以。
//int cnt=lower_bound(b+1,b+1+d,h[i])-b;
  int cnt=upper_bound(b+1,b+1+d,h[i])-b-1;

以上兩種都是對的。

代碼:

  1 //無修改區間-可持久化線段樹(權值線段樹+可持久化)
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<bitset>
  7 #include<cassert>
  8 #include<cctype>
  9 #include<cmath>
 10 #include<cstdlib>
 11 #include<ctime>
 12 #include<deque>
 13 #include<iomanip>
 14 #include<list>
 15 #include<map>
 16 #include<queue>
 17 #include<set>
 18 #include<stack>
 19 #include<vector>
 20 using namespace std;
 21 typedef long long ll;
 22 typedef pair<int,int> pii;
 23 
 24 const double PI=acos(-1.0);
 25 const double eps=1e-6;
 26 const ll mod=1e9+7;
 27 const int inf=0x3f3f3f3f;
 28 const int maxn=2e5+10;
 29 const int maxm=100+10;
 30 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 31 #define lson l,m
 32 #define rson m+1,r
 33 
 34 int a[maxn],b[maxn],sum[maxn<<5],ls[maxn<<5],rs[maxn<<5];//sum線段樹裏保存的值,L左兒子,R右兒子
 35 int n,m,sz=0;
 36 
 37 void build(int &rt,int l,int r)//建棵空樹
 38 {
 39     rt=++sz;sum[rt]=0;//動態開點,初始值為0,空樹
 40     if(l==r){
 41         return ;
 42     }
 43 
 44     int m=(l+r)>>1;
 45     build(ls[rt],lson);
 46     build(rs[rt],rson);
 47 }
 48 
 49 void update(int pre,int &rt,int l,int r,int p,int c)
 50 {
 51     rt=++sz;sum[rt]=sum[pre]+c;//插入序列,首先繼承以前的線段樹 然後直接單點+1就可以
 52     ls[rt]=ls[pre];rs[rt]=rs[pre];
 53     if(l==r){
 54         return ;
 55     }
 56 
 57     int m=(l+r)>>1;
 58     if(p<=m) update(ls[pre],ls[rt],lson,p,c);//因為右邊不需要更新,所以覆蓋掉左邊
 59     else     update(rs[pre],rs[rt],rson,p,c);
 60     //sum[rt]=sum[ls[rt]]+sum[rs[rt]];
 61 }
 62 
 63 int query(int pre,int rt,int L,int R,int l,int r)//查詢l到r區間就是第r次插入減去第l-1次插入後的線段樹的樣子
 64 {
 65     if(L>R) return 0;
 66     if(L<=l&&r<=R){
 67         return sum[rt]-sum[pre];
 68     }
 69 
 70     int ret=0;
 71     int m=(l+r)>>1;
 72     if(L<=m) ret+=query(ls[pre],ls[rt],L,R,lson);
 73     if(R> m) ret+=query(rs[pre],rs[rt],L,R,rson);
 74     return ret;
 75 }
 76 
 77 int rt[maxn],l[maxn],r[maxn],h[maxn];
 78 
 79 int main()
 80 {
 81     int t;
 82     scanf("%d",&t);
 83     for(int cas=1;cas<=t;cas++){
 84         scanf("%d%d",&n,&m);
 85         sz=0;
 86         for(int i=1;i<=n;i++)
 87         {
 88             scanf("%d",&a[i]);
 89             b[i]=a[i];
 90         }
 91         for(int i=1;i<=m;i++){
 92             scanf("%d%d%d",&l[i],&r[i],&h[i]);
 93             b[i+n]=h[i];
 94             l[i]++,r[i]++;
 95         }
 96         sort(b+1,b+1+n+m);//首先把值全部排序去重,用於建權值線段樹,權值線段樹保存的內容是值的數量。
 97         int d=unique(b+1,b+1+n+m)-(b+1);
 98         build(rt[0],1,d);
 99         for(int i=1;i<=n;i++) //按照序列順序插入值
100         {
101             int p=lower_bound(b+1,b+1+d,a[i])-b;
102             update(rt[i-1],rt[i],1,d,p,1);
103         }
104         printf("Case %d:\n",cas);
105         for(int i=1;i<=m;i++)
106         {
107             //int L=1,R=upper_bound(b+1,b+1+d,h)-b-1;
108             //int cnt=lower_bound(b+1,b+1+d,h[i])-b;
109             int cnt=upper_bound(b+1,b+1+d,h[i])-b-1;
110             //printf("%d\n",query(rt[l[i]],rt[r[i]+1],1,cnt,1,d));
111             //printf("%d\n",query(rt[l],rt[r+1],1,cnt,1,d));
112             printf("%d\n",query(rt[l[i]-1],rt[r[i]],1,cnt,1,d));
113         }
114     }
115     return 0;
116 }

菜的難受。。。

HDU 4417.Super Mario-無修改區間小於等於H的數的個數-可持久化線段樹