线段树求解区间不相同数的和

hdoj 3333 http://acm.hdu.edu.cn/showproblem.php?pid=3333

题意:输入t表示又t组 输入n  后面又n个数 输入m表示下面又m组询问  每组询问包含一个区间求区间

分析 最简单方法暴力。。数据大肯定超时。故离散化处理。。 先对n个数排序 把相同的数去掉  在对询问按末尾排序 用线段树求之。。把序列遍历一遍。当前面有跟当前数相同的数的时候更新线段树。这样可以导致相同数离区间末尾最近查询就能查到正确结果。比如1 1 2 1 1 2 1 当遍历到第三个数而且查询区间2 3的时候 第二个1离3的位置最近。所以把前面的1去掉。。要是把第2个1取了的话、查询2 3 的时候结果是3 就错了

注意当遍历到某个位置的时候看有没有查询区间末尾是这个位置的。要是是的话。前面已经都处理完。那么重复的数离当前区间肯定是最近的故求之

献上ac代码

  1 //注意题目数据大用long long 
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<string.h>
  5 #include<iostream>
  6 using namespace std;
  7  
  8 int num[40005], s[40005], vis[40005];
  9 int sign1, n, m;
 10 long long ans[200010];
 11 
 12 struct st
 13 {
 14     long long sum;
 15     int l, r;
 16 }tree[40001<<2];
 17 
 18 struct stt
 19 {
 20     int start;
 21     int end;
 22     int id;
 23 }p[200010];
 24 
 25 int cam(const void *x,const void *y)
 26 {
 27     return *(int *)x-*(int *)y;
 28 }
 29 
 30 
 31 int cam1(const void *x,const void *y)
 32 {
 33     struct stt p = *((struct stt*)x);
 34     struct stt q = *((struct stt*)y);
 35     return p.end-q.end;
 36     
 37 }
 38 
 39 void push_up(int x)
 40 {
 41     tree[x].sum = tree[x<<1].sum+tree[x<<1|1].sum;
 42 }
 43 
 44 void build(int l,int r,int cn)
 45 {
 46     
 47     if(l==r)
 48     {
 49         tree[cn].sum=num[l];
 50         return ;
 51     }
 52     
 53     int mid = (l+r)>>1;
 54     tree[cn].l=l;
 55     tree[cn].r=r;
 56     build(l,mid,cn<<1);
 57     build(mid+1,r,cn<<1|1);
 58     push_up(cn);
 59     
 60 }
 61 
 62 void update(int l, int r, int cn, int a)
 63 {
 64     if(l==r)
 65     {
 66         tree[cn].sum-=num[a];
 67         return;
 68     }
 69     int mid = (l+r)>>1;
 70     if(mid>=a)
 71      update(l,mid,cn<<1,a);
 72     else
 73      update(mid+1,r,cn<<1|1,a);    
 74     push_up(cn);
 75 }
 76 
 77 long long query(int l, int r,int start,int end,int cn)
 78 {
 79     if(l==start&&r==end)
 80     {
 81         return tree[cn].sum;
 82     }
 83     int mid = (l+r)>>1;
 84     if(mid>=end)
 85     {
 86         return query(l,mid,start,end,cn<<1);
 87     }
 88     else if(mid<start)
 89     {
 90         return query(mid+1,r,start,end,cn<<1|1);
 91     }
 92     else
 93     {
 94         return query(l,mid,start,mid,cn<<1)+query(mid+1,r,mid+1,end,cn<<1|1);
 95     }
 96 
 97 
 98 }
 99 int bin(int a)//二分查找num[i]在s数组的位置 
100 {
101     int l = 1, r = sign1;
102     while(l<=r)
103     {
104         int mid = (l+r)>>1;
105         if(s[mid]==a) 
106           return mid;
107         
108         if(s[mid]<a) 
109           l=mid+1;
110           
111         if(s[mid]>a) 
112           r=mid-1;         
113     }
114 }
115 
116 void solve()
117 {
118     int i, j=0;
119     memset(vis,0,sizeof(vis));
120     for(i=1;i<=n;i++)
121     {
122         int temp = bin(num[i]);
123 
124         if(!vis[temp])//记录前面一次出现的位置 
125         {
126             vis[temp]=i;       
127         }
128         else
129         {
130             update(1,n,1,vis[temp]);
131             vis[temp]=i;
132         }
133         for(;j<m;j++)
134         {
135             //printf("%d %d\n",p[j].end,i);
136             if(p[j].end==i)//要是当前区间末尾正是的话求之 
137             {
138                 //printf("%d\n",query(1,n,p[j].start,p[j].end,1));
139                 ans[p[j].id]=query(1,n,p[j].start,p[j].end,1);
140             }
141             else
142             {
143                 break;
144             }
145         }  
146         
147     }
148 }
149 
150 void printt()//输出答案 
151 {
152     int i;
153     for(i=0;i<m;i++)
154      printf("%I64d\n",ans[i]);
155 }
156 
157 int main()
158 {
159     int t;
160     scanf("%d",&t);
161     while(t--)
162     {
163         scanf("%d",&n);
164         int i;
165         for(i=1;i<=n;i++)
166         {
167            scanf("%d",&num[i]);
168            s[i]=num[i];
169         }
170         build(1,n,1);
171         
172         qsort(&s[1],n,sizeof(s[1]),cam);
173         
174         sign1=2;
175         
176         for(i=2;i<=n;i++)
177         {
178               if(s[i]!=s[i-1])
179                   s[sign1++]=s[i];//取相同元素 
180         }
181             
182             sign1--;
183             scanf("%d",&m);
184         for(i=0;i<m;i++)
185         {
186              scanf("%d %d",&p[i].start,&p[i].end);//按末尾排序 
187              p[i].id=i;
188         }
189         
190         qsort(p,m,sizeof(p[0]),cam1);
191         solve();
192         printt();
193             
194     }
195 
196     return 0;
197 }

 

posted on 2012-10-12 23:09  acmer_acm  阅读(1499)  评论(0编辑  收藏  举报