hdu 3333 Turing Tree 图灵树(线段树 + 二分离散)
http://acm.hdu.edu.cn/showproblem.php?pid=3333
Turing Tree
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2614 Accepted Submission(s): 892
Now given a sequence of N numbers A1, A2, ..., AN and a number of Queries(i, j) (1≤i≤j≤N). For each Query(i, j), you are to caculate the sum of distinct values in the subsequence Ai, Ai+1, ..., Aj.
很不错的一道线段树题目,做了两天,终于给弄明白了。。。
看别人blog的时候,发现总是说离散化,,不明白什么意思。。。上网搜了下,其实就是一种思想的转化,,有时候我们一直在用,只不过不知道叫什么名字罢了。。。
比如对于这道题, 我们如果讨论一个数,判断它前面是否出现过,,因为0 ≤ Ai ≤ 1,000,000,000 ,很显然我们不能直接 用一个visit去判断。。
但是由于1 ≤ N ≤ 30,000 ,我们可以开一个30000的数组,然后把这些数存起来,排好序, 之后再判断一个数是否出现过的时候, 就可以用二分找到它的下标。。
对下表进行visit记录就可以了。。。
题意: 给出一个长度为N(N <= 30000)的数列,然后是一连串询问,询问数<= 100000,问给定区间内不同数字的和。
因为数字的范围较大,所以首先是对数列进行离散化,一般可以用二分或者hash,将大范围的数字映射到连续的区间。
然后一次性读入所有的区间(整数对),并且对整数对的右端点进行递增排序。这里注意,要记录下整数对读入的位置下标。。。
接下来按顺序枚举每个数字a[i],如果a[i]之前出现过,就将a[i]之前位置的值删除,然后在当前位置插入,当枚举的位置和区间对中某个位置相 等时执行询问操作。。。。
题解部分转自:http://www.cnblogs.com/183zyz/archive/2011/04/22/2025060.html
【code】:
1 /** 2 judge status: Accepted exe.time:640ms 3 exe.memory 3696k language:C++ 4 */ 5 6 #include<iostream> 7 #include<stdio.h> 8 #include<string.h> 9 #include<algorithm> 10 11 #define N 100010 12 #define M 30010 13 14 #define lson p<<1 15 #define rson p<<1|1 16 17 using namespace std; 18 19 struct FTI{ 20 int from,to,idx; //查询的始末位置 以及 索引位置 21 }fti[N]; 22 23 struct Nod{ 24 int l,r; 25 __int64 sum; 26 }node[M<<2]; 27 28 int temp[M],index[M],a[M],visit[M],k; 29 30 __int64 ans[N]; 31 32 bool cmp(FTI a,FTI b) //结构体排序调用函数 33 { 34 return a.to<b.to; 35 } 36 37 void building(int l,int r,int p) 38 { 39 node[p].sum=0; 40 node[p].l=l; 41 node[p].r=r; 42 if(l==r) return; 43 int mid=(l+r)/2; 44 building(l,mid,lson); 45 building(mid+1,r,rson); 46 } 47 48 int findPos(int val) //二分查找值val在index中的位置 49 { 50 int l,r,mid; 51 l=1; 52 r=k; 53 while(l<=r) 54 { 55 mid=(l+r)/2; 56 if(index[mid]>val) r=mid-1; 57 else if(index[mid]<val) l=mid+1; 58 else return mid; 59 } 60 return -1; 61 } 62 63 void update(int id,int p,int val) //更新 64 { 65 if(node[p].l==node[p].r) 66 { 67 node[p].sum+=val; 68 return; 69 } 70 int mid = (node[p].l+node[p].r)>>1; 71 if(id<=mid) update(id,lson,val); 72 else update(id,rson,val); 73 node[p].sum = node[lson].sum + node[rson].sum; 74 } 75 76 __int64 Query(int l,int r,int p) 77 { 78 if(node[p].l==l&&node[p].r==r) 79 { 80 return node[p].sum; 81 } 82 int mid = (node[p].l+node[p].r)>>1; 83 if(r<=mid) return Query(l,r,lson); 84 else if(l>mid) return Query(l,r,rson); 85 else return Query(l,mid,lson)+Query(mid+1,r,rson); 86 } 87 88 int main() 89 { 90 int t; 91 scanf("%d",&t); 92 while(t--) 93 { 94 int n,i,j; 95 scanf("%d",&n); 96 for(i=0;i<n;i++) 97 { 98 scanf("%d",a+i+1); 99 temp[i]=a[i+1]; 100 } 101 sort(temp,temp+n);//排序 102 index[1]=temp[0]; 103 j=1; 104 for(i=1;i<n;i++) 105 { 106 if(index[j]!=temp[i]) 107 { 108 index[++j]=temp[i]; //消除重复数字 109 } 110 } 111 k=j; 112 memset(visit,0,sizeof(visit)); 113 int m; 114 scanf("%d",&m); 115 for(i=1;i<=m;i++) 116 { 117 scanf("%d%d",&fti[i].from,&fti[i].to); 118 fti[i].idx = i; 119 } 120 sort(fti+1,fti+m+1,cmp); //结构体按to排序 121 building(1,n,1); 122 j=1; 123 int id,pos; 124 for(i=1;i<=n;i++) 125 { 126 id = findPos(a[i]); 127 pos = visit[id]; 128 if(pos) update(pos,1,-a[i]); //如果前面出现过a[i],则减掉前面的a[i] 129 update(i,1,a[i]); //在i的位置增加a[i] 130 visit[id] = i; //标记出现过 131 while(j<=m&&i==fti[j].to) 132 { 133 ans[fti[j].idx] = Query(fti[j].from,fti[j].to,1); //如果到了to的位置,就是需要统计的时候了,结果放到ans里面 134 j++; 135 } 136 } 137 for(i=1;i<=m;i++) 138 { 139 printf("%I64d\n",ans[i]); 140 } 141 } 142 return 0; 143 }