[SDOI2009]HH的项链-树状数组/线段树

树状数组:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 1000010;
 4 int id[maxn],tree[maxn],vis[maxn],num[maxn];
 5 int n,m;
 6 struct Tree{
 7     int l,r;
 8     int pos;
 9 };
10 Tree a[maxn];
11 int buf[17];
12 inline void read(int &x){
13     char ch=getchar(); x=0;
14     while(ch<‘0‘) ch=getchar();
15     while(ch>=‘0‘ && ch<=‘9‘) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
16 }
17 inline void write(int x){
18     if(!x){putchar(‘0‘);putchar(‘ ‘);return;}
19     register int cnt=0;
20     while(x)buf[++cnt]=(x%10)+48,x/=10;
21     while(cnt)putchar(buf[cnt--]);
22     putchar(‘\n‘);
23 }
24 bool cmp(Tree x,Tree y){
25     return x.r < y.r;
26 }
27 int lowbit(int x){
28     return x & -x;
29 }
30 void add(int x,int now){
31     while(x <= n){
32         tree[x] += now;
33         x += lowbit(x);
34     }
35 }
36 int sum(int n){
37     int ans = 0;
38     while(n != 0){
39         ans += tree[n];
40         n -= lowbit(n);
41     }
42     return ans;
43 }
44 int main(){
45     read(n);
46     for(int i = 1;i <= n;i++)
47         read(id[i]);
48     read(m);
49     for(int i = 1;i <= m;i++){
50         read(a[i].l);
51         read(a[i].r);
52         a[i].pos = i;
53     }
54     sort(a+1,a+1+m,cmp);
55     int next = 1;
56     for(int i = 1;i <= m;i++){
57         for(int j = next;j <= a[i].r;j++){
58             if(vis[id[j]])
59                 add(vis[id[j]],-1);
60             add(j,1);
61             vis[id[j]] = j;
62         }
63         next = a[i].r+1;
64         num[a[i].pos] = sum(a[i].r)-sum(a[i].l-1);
65     }
66     for(int i = 1;i <= m;i++)
67         write(num[i]);
68     return  0;
69 }

线段树:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 5e6+5;
 4 struct segment_tree{
 5     int l,r,s,sum;
 6 };
 7 segment_tree ask[maxn<<2],tree[maxn<<2];
 8 int next[maxn],pre[maxn],a[maxn],x[maxn],n,m;
 9 int buf[17];
10 inline void read(int &x){
11     char ch=getchar(); x=0;
12     while(ch<‘0‘) ch=getchar();
13     while(ch>=‘0‘ && ch<=‘9‘) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
14 }
15 inline void write(int x){
16     if(!x){putchar(‘0‘);putchar(‘ ‘);return;}
17     register int cnt=0;
18     while(x)buf[++cnt]=(x%10)+48,x/=10;
19     while(cnt)putchar(buf[cnt--]);
20     putchar(‘\n‘);
21 }
22 bool cmp1(segment_tree x,segment_tree y){
23     if (x.l == y.l)return x.r < y.r;
24     else return x.l < y.l;
25 }
26 bool cmp2(segment_tree x,segment_tree y){
27     return x.s < y.s;
28 }
29 inline void pushup(int root){
30     tree[root].sum = tree[root<<1].sum+tree[root<<1|1].sum;
31 }
32 inline void build(int root,int l,int r){
33     tree[root].l = l;
34     tree[root].r = r;
35     if(l == r){
36         tree[root].sum = a[l];
37         return;
38     }
39     int mid = (l+r)>>1;
40     build(root<<1,l,mid);
41     build(root<<1|1,mid+1,r);
42     pushup(root);
43 }
44 inline void update(int root,int k){
45     if (tree[root].l == k && tree[root].r == k){
46         a[k] = 1;
47         tree[root].sum = a[k];
48         return;
49     }
50     int mid = (tree[root].l+tree[root].r)>>1;
51     if(k <= mid)update(root<<1,k);
52     else update(root<<1|1,k);
53     pushup(root);
54 }
55 inline int query(int root,int l,int r){
56     if(tree[root].l == l && tree[root].r == r)
57         return tree[root].sum;
58     int mid = (tree[root].l+tree[root].r)>>1;
59     if(r <= mid)return query(root<<1,l,r);
60     else
61         if(l > mid)return query(root<<1|1,l,r);
62         else return(query(root<<1,l,mid)+query(root<<1|1,mid+1,r));
63 }
64 int main(){
65     read(n);
66     for(register int i = 1;i <= n;i++){
67         read(x[i]);
68         next[pre[x[i]]] = i;
69         if(!pre[x[i]])a[i] = 1;
70         pre[x[i]] = i;
71     }
72     build(1,1,n);
73     scanf("%d",&m);
74     for(register int i = 1;i <= m;i++){
75         read(ask[i].l);
76         read(ask[i].r);
77         ask[i].s = i;
78     }
79     sort(ask+1,ask+m+1,cmp1);
80     ask[0].l = 1;
81     for(register int i = 1;i <= m;i++){
82         if(ask[i-1].l != ask[i].l)
83             for(register int j = ask[i-1].l;j <= ask[i].l-1;j++)
84                 if(next[j])update(1,next[j]);
85         ask[i].sum = query(1,ask[i].l,ask[i].r);
86     }
87     sort(ask+1,ask+m+1,cmp2);
88     for(register int i=1;i<=m;i++)
89         write(ask[i].sum);
90     return 0;
91 }

别问我为什么补贴出来分块做法...

因为没学懂!!!没打出来!!!好不容易打出来,给我超时!!!气死了!!!

原文地址:https://www.cnblogs.com/wangyifan124/p/10320268.html

时间: 2024-08-10 21:20:16

[SDOI2009]HH的项链-树状数组/线段树的相关文章

hdu 1166 树状数组 线段树

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 51177    Accepted Submission(s): 21427 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

hdu1394(枚举/树状数组/线段树单点更新&amp;区间求和)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 或 -1, 交换两个不相邻数 a, b, 逆序数 += 两者间大于 a 的个数 - 两者间小于 a 的个数: 所以只要求出初始时的逆序对数,就可以推出其余情况时的逆序对数.对于求初始逆序对数,这里 n 只有 5e3,可以直接暴力 / 树状数组 / 线段树 / 归并排序: 代码: 1.直接暴力 1

HDU 1394 Minimum Inversion Number 树状数组&amp;&amp;线段树

题目给了你一串序列,然后每次 把最后一个数提到最前面来,直到原来的第一个数到了最后一个,每次操作都会产生一个新的序列,这个序列具有一个逆序数的值,问最小的你逆序数的值为多少 逆序数么 最好想到的是树状数组,敲了一把很快,注意把握把最后一个数提上来对逆序数的影响即可, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #i

HDU 1166 敌兵布阵 (树状数组&#183;线段树)

题意  中文 动态区间和问题   只会更新点  最基础的树状数组 线段树的应用 树状数组代码 #include <bits/stdc++.h> using namespace std; const int N = 50005; int c[N], n, m; void add(int p, int x) { while(p <= n) c[p] += x, p += p & -p; } int getSum(int p) { int ret = 0; while(p > 0

Curious Robin Hood(树状数组+线段树)

1112 - Curious Robin Hood    PDF (English) Statistics Forum Time Limit: 1 second(s) Memory Limit: 64 MB Robin Hood likes to loot rich people since he helps the poor people with this money. Instead of keeping all the money together he does another tri

士兵杀敌(四)(树状数组+线段树)

士兵杀敌(四) 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 南将军麾下有百万精兵,现已知共有M个士兵,编号为1~M,每次有任务的时候,总会有一批编号连在一起人请战(编号相近的人经常在一块,相互之间比较熟悉),最终他们获得的军功,也将会平分到每个人身上,这样,有时候,计算他们中的哪一个人到底有多少军功就是一个比较困难的事情,军师小工的任务就是在南将军询问他某个人的军功的时候,快速的报出此人的军功,请你编写一个程序来帮助小工吧. 假设起始时所有人的军功都是0. 输入

Color the ball(树状数组+线段树)

Color the ball Time Limit : 9000/3000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 3   Accepted Submission(s) : 1 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b

Codeforces Round #225 (Div. 1) C 树状数组 || 线段树

看到这题很开心啊,有印象跟以前做过的很像,貌似最近就做过一个,以时间戳为区间来建立树状数组,然后一开始我以为题意是,给x点加val,它以下的所有节点都加-val:所以一开始就以 加 和 减 建立了两个树状数组,最后 减去就是答案,写完发现跟案例对不上啊,读了题目也没发现读错了,对于那句话 我理解错了,后来看了 这个: http://blog.csdn.net/keshuai19940722/article/details/18967661 仔细看看处理部分,我还以为分奇偶性有规律呢,后来才发现读

HDU 4417 Super Mario (树状数组/线段树)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Description Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble agai