hdu3333-Turing Tree-线段树+离线+离散化

前言:引用某某的话——我是猪QAQ。。。。。

题意就不复述了。

解题思路:

一般的建树,求和。

离散化:用另一个数组sor[]记录原数组,sort一遍,用unique去重,用sor[]数组元素下标,代替原数组中元素,然后在sor[]数组里二分查找元素,last[]数组记录第i个元素上一次出现的位置。

离线处理:将查询按右边界从小到大排序,依次处理区间[1, r1]、[r1+1, r2]、[r2+1, r3]......将重复的元素的前一个(记录在last里)在线段树里单点更新删去, 然后将query(li, ri)的值记录到相应的位置。同时,在读入时记录是第几个查询用于后面输出。

复杂度:O(nlogn)

AC代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <vector>
  4 #include <cstring>
  5 #include <algorithm>
  6 using namespace std;
  7 #define lson l, m, rt<<1
  8 #define rson m+1, r, rt<<1|1
  9 int n, m;
 10 struct node
 11 {
 12     int l, r;
 13     int num;
 14     bool operator < (const node that) const{
 15         return r < that.r;
 16     }
 17 };
 18 bool uni(int i, int j)
 19 {
 20     return i == j;
 21 }
 22 vector<node> brr;
 23 vector<int> sor;
 24 vector<int> arr;
 25 long long sgt[1200080];
 26 int last[30005];
 27 long long ans[300005];
 28 void input()
 29 {
 30     brr.clear(); sor.clear(); arr.clear();
 31     memset(last, -1, sizeof(last));
 32     scanf("%d", &n);
 33     for(int i = 0; i < n; i++) {
 34         int a; scanf("%d", &a);
 35         arr.push_back(a);
 36         sor.push_back(a);
 37     }
 38     sort(sor.begin(), sor.end());
 39     vector<int>::iterator it;
 40     it = unique(sor.begin(), sor.end(), uni);
 41     sor.resize(distance(sor.begin(), it)); //离散化
 42     scanf("%d", &m);
 43     for(int i = 0; i < m; i++) {
 44         node x; scanf("%d%d", &x.l, &x.r);
 45         x.num = i;   //记录询问的顺序
 46         brr.push_back(x);
 47     }
 48     sort(brr.begin(), brr.end());
 49 }
 50 void push_up(int rt)
 51 {
 52     sgt[rt] = sgt[rt<<1] + sgt[rt<<1|1];
 53 }
 54 void build(int l, int r, int rt)
 55 {
 56     if(l == r) {
 57         sgt[rt] = arr[l-1];
 58         return;
 59     }
 60     int m = (l + r)>>1;
 61     build(lson);
 62     build(rson);
 63     push_up(rt);
 64 }
 65 void Delete(int l, int r, int rt, int pos)
 66 {
 67     if(l == r) {
 68         sgt[rt] = 0; return ;
 69     }
 70     int m = (l+r)>>1;
 71     if(pos <= m) Delete(lson, pos);
 72     else Delete(rson, pos);
 73     push_up(rt);
 74 }
 75 long long query(int l, int r, int rt, int L, int R)
 76 {
 77     if(L <= l && r <= R) {
 78         return sgt[rt];
 79     }
 80     long long res = 0;
 81     int m = (l+r)>>1;
 82     if(L <= m) res += query(lson, L, R);
 83     if(m < R) res += query(rson, L, R);
 84     return res;
 85 }
 86 
 87 void work()
 88 {
 89     build(1, n, 1);
 90     int l, r;
 91     for(int i = 0; i < m; i++) {
 92         r = brr[i].r-1;
 93         if(i == 0) l = 0;
 94         else l = brr[i-1].r;
 95         for(int j = l; j <= r; j++) {
 96             int pos = lower_bound(sor.begin(), sor.end(), arr[j]) - sor.begin();   //pos对应离散化后的元素下标
 97             if(last[pos] == -1) {   //前面无重复
 98                 last[pos] = j; continue;
 99             }
100             Delete(1, n, 1, last[pos]+1); last[pos] = j;  //删除重复元素,更改last为元素当前位置。
101         }
102         ans[brr[i].num] = query(1, n, 1, brr[i].l, brr[i].r);   //将结果填在询问的顺序位置
103     }
104     for(int i = 0; i < m; i++) {
105         printf("%I64d\n", ans[i]);
106     }
107 }
108 int main()
109 {
110     int t; cin>>t;
111     while(t--) {
112         input();
113         work();
114     }
115     return 0;
116 }
View Code

 

转载于:https://www.cnblogs.com/ZiningTang/p/3956788.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值