UVA1513 Movie collection

传送门

题意

KI先生有收集大量小电影的习惯, 他把他的珍藏理成一大摞。无论何时他想观看这一些电影的一部,他从这一摞电影中找出这一部电影,小心地将其拿出,以确保这一摞电影不会倒塌.

自从那一摞电影变得越来越大,他需要跟踪每一部电影的位置.或许了解每一部电影上面有多少部电影,就足以根据这些信息计算出其在这一摞电影中的位置.由一个印在电影盒子上的数字,可以识别出每一部电影.

那么你的任务就是编写一个跟踪每一部电影位置的程序,特别的,当KI先生从这一摞电影中拿出一部时,你的程序必须打印出在这一部即将被拿出的电影上面电影的数目.

输入

第一行是一个正整数t:输入数据的数量(t<=100),之后每一个测试数据,一行上是两个整数n,m, (1 ≤ n, m ≤ 100000),他们表示这一摞电影的数量和电影查询请求的数量.另一行是有m个整数, a1, . . . , am (1 ≤ ai ≤ n),他们表示KI先生想看的电影,它们需要你去查询定位.

为了简单起见,假设这一摞电影的编号1,2……n按顺序增加,其中这一摞电影最上面的是1号电影.

输出

每一组数据,输出一行整数, 其中第i个整数给出ai号电影在被拿出之前上方的电影的数目。请注意,在每次查询请求ai之后,ai号电影会被放在这一摞电影的顶部

Sample Input
2
3 3
3 1 1
5 3
4 4 5


Sample Output
2 1 0
3 0 4

一道不错的思维题,这道题目的修改和查询操作比较简单,就是在拿出一张电影时,查询在它前面有多少元素,然后把它前面的数的位置都向后移动一位,但是我们如何实现将这张电影放到顶部呢?这不是删除和插入操作吗?然而我不会平衡树啊!!!于是这里有一种十分神奇的做法,可以巧妙的解决这个问题。由于要查询m次,也就是说我们要移动m次电影,所以我们可以开一个大小为(n+m)的树状数组,把每个数的权设为1,开始我们把n个数放在m+1---m+n的区间上,然后每进行一次查询a[i]作我们就将a[i]所在的位置-1,并把a[i]放到最前面,这样只需要不断地将元素前移就可以巧妙的解决问题了。

注意:uva对行末空格十分敏感,所以不能输出多余的空格。

 1 #include<iostream>
 2 #include<string>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<map>
 7 #include<algorithm>
 8 #include<stack>
 9 #include<queue>
10 #include<vector>
11 #define maxn 200005
12 using namespace std;
13 
14 inline int read()
15 {
16     int x=1,res=0;
17     char c=getchar();
18     while(c<'0'||c>'9')
19     {
20         if(c=='-')
21         x=-1;
22         c=getchar();
23     }
24     while(c>='0'&&c<='9')
25     {
26         res=res*10+(c-'0');
27         c=getchar();
28     }
29     return res*x;
30 }
31 
32 int T,n,m,aa;
33 int c[maxn<<1],a[maxn];
34 
35 int low(int x)
36 {
37     return x&(-x);
38 }
39 
40 void add(int x,int y)
41 {
42     for(int i=x;i<=n+m;i+=low(i))
43     {
44         c[i]+=y;
45     }
46 }
47 
48 int ask(int x)
49 {
50     int ans=0;
51     for(int i=x;i>0;i-=low(i))
52     {
53         ans+=c[i];
54     }
55     return ans;
56 }
57 
58 int main()
59 {
60     T=read();
61     while(T--)
62     {
63         n=read();m=read();
64         memset(c,0,sizeof(c));
65         int pd=0;
66         for(int i=m+1;i<=m+n;i++)
67         {
68             a[i-m]=i;
69             add(i,1);
70         }
71         for(int i=1;i<=m;i++)
72         {
73             aa=read();
74             if(pd==0)
75             {
76                 pd=1;
77             }
78             else 
79             {
80                 printf(" ");
81             }
82             printf("%d",ask(a[aa]-1));
83             add(a[aa],-1);
84             a[aa]=(m+1-i);
85             add(a[aa],1);
86         }
87         printf("\n");
88     }
89     return 0;
90 }
View Code

猜你喜欢

转载自www.cnblogs.com/snowy2002/p/10387986.html
今日推荐