线段树求解区间不相同数的和
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) 编辑 收藏 举报