HYSBZ 4551 (树状数组) 采花

题目:这里

题意:

在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下

两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个

结点,可以打多次标记。)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖

先)你能帮帮他吗?

Input

输入第一行两个正整数N和Q分别表示节点个数和操作次数接下来N-1行,每行两个正整数u,v(1≤u,v≤n)表示u到v

有一条有向边接下来Q行,形如“opernum”oper为“C”时表示这是一个标记操作,oper为“Q”时表示这是一个询

问操作对于每次询问操作,1 ≤ N, Q ≤ 100000。

Output

输出一个正整数,表示结果

Sample Input

5 5
1 2
1 3
2 4
2 5
Q 2
C 2
Q 2
Q 5
Q 3

Sample Output

1
2
2
1

HINT

明显与两个相同的数在数组中的位置有关系。

求出颜色数组的前缀(前面一个该颜色值的位置)或者后缀(后一个该颜色的位置,以后缀为例),这里可以用树状数组解决,将给没个询问区间按照左范围从小到大

排序,然后遍历一边大区间1到n,当 i 小于询问范围左端点的的时候将其加入树状数组,等于询问范围左端点的时候既求区间范围和,注意的是,由于只有同种

颜色的花的数目大于1才算,所以事先将符合条件的花先加进数组,然后遍历的时候考虑失去 i 这个位置的时候是加一还是减一

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6
 7 const int M = 1e6 + 10;
 8 int has[M],has1[M],vis[M],b[M],ans[M],n;
 9 int q[M];
10
11 struct node{
12    int x,y,id;
13 }a[M];
14
15 int lowbit(int x){return x&(-x);}
16
17 void add(int x,int y)
18 {
19     while (x<=M){
20         has[x]+=y;
21         x+=lowbit(x);
22     }
23 }
24
25 int getsum(int x)
26 {
27     int ans=0;
28     while (x>0){
29         ans+=has[x];
30         x-=lowbit(x);
31     }
32     return ans;
33 }
34
35 bool cmp(node a,node b)
36 {
37     if (a.x==b.x) return a.y<b.y;
38     return a.x<b.x;
39 }
40
41 int main()
42 {
43     int c,m;
44     bool flag=false;
45     scanf("%d%d%d",&n,&c,&m);
46     memset(vis,0,sizeof(vis));
47     memset(has1,0,sizeof(has1));
48     for (int i=1 ; i<=n ; i++){
49         scanf("%d",&b[i]);
50         /*if (has1[b[i]]==0) vis[i]=i,has1[b[i]]=i;
51         else{
52             vis[i]=has1[b[i]];
53             has1[b[i]]=i;
54         }*/
55     }
56     for(int i=n ;i>=1 ; i--){  //求后缀
57       vis[i]=has1[b[i]];
58       has1[b[i]]=i;
59    }
60     for (int i=1 ; i<=m ; i++){
61         scanf("%d%d",&a[i].x,&a[i].y);
62         a[i].id=i;
63     }
64     for(int i=1 ; i<=c ; i++){ //满足的先加上
65       if (vis[has1[i]])
66          add(vis[has1[i]],1);
67       //cout<<has1[i]<<endl;
68     }
69     sort(a+1,a+m+1,cmp);
70     int j=1;
71    // memset(q,0,sizeof(q));
72     for(int i=1 ; i<=m ; i++){
73       while (j<a[i].x){
74          if (vis[vis[j]])add(vis[vis[j]],1);
75          if (vis[j])  add(vis[j],-1);
76          j++;
77       }
78        ans[a[i].id]=getsum(a[i].y)-getsum(a[i].x-1);
79    }
80     for (int i=1 ; i<=m ; i++){
81         printf("%d\n",ans[i]);
82     }
83     //cout<<getsum(1)<<endl;
84     return 0;
85 }

时间: 2024-10-13 01:13:30

HYSBZ 4551 (树状数组) 采花的相关文章

BZOJ_2743_[HEOI2012]采花_离线+树状数组

Description 萧芸斓是Z国的公主,平时的一大爱好是采花.今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花 .花园足够大,容纳了n朵花,花有c种颜色(用整数1-c表示),且花是排成一排的,以便于公主采花.公主每次 采花后会统计采到的花的颜色数,颜色数越多她会越高兴!同时,她有一癖好,她不允许最后自己采到的花中,某 一颜色的花只有一朵.为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必 能再次采到此颜色的花.由于时间关系,公主只能走过花园连续的一段进

[HEOI2012]采花 树状数组

题目描述 萧薰儿是古国的公主,平时的一大爱好是采花. 今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花. 花园足够大,容纳了n朵花,花有c种颜色(用整数1-c表示),且花是排成一排的,以便于公主采花.公主每次采花后会统计采到的花的颜色数,颜色数越多她会越高兴!同时,她有一癖好,她不允许最后自己采到的花中,某一颜色的花只有一朵.为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必能再次采到此颜色的花. 由于时间关系,公主只能走过花园连续的一段进行采花,便让女仆

bzoj2743: [HEOI2012]采花--离线树状数组+差分

题目大意:给定一个区间,查询子区间里出现次数不小于二的数的个数 此题想了好久没想出来,后来是在网上学习的一个方法 首先按查询区间的右端点进行排序,按右端点从小到大处理 假设pre[a[i]]是与a[i]相同的前一个数的位置,记为left[i] 当查询到第i个数时,对left[left[i]]+1~left[i]的每个数的权值w[]加1 也就是说:左端点在left[left[i]]+1~left[i]内,右端点为i的区间里,出现次数不小于二的数+1 那么对于查询i,答案就是w[left[i]] 因

BZOJ 2743 HEOI2012 采花 树状数组

题目大意:给定一个序列,多次询问区间内出现两次以上的数的数量 n<=100W 莫队不用想了 考虑对于每个区间的左端点 对这个区间有贡献的数是从这个端点开始所有第二次出现的数 于是我们将区间按照左端点排序  然后从左向右扫 令next[i]为i位置上的数下一次出现的位置 初始将所有第二次出现的数加入树状数组 然后每删除一个点i 将next[i]从树状数组中删除 然后将next[next[i]]加入树状数组 然后处理区间就在树状数组上查询右端点即可 #include<cstdio> #inc

Luogu4113 HEOI2012 采花 树状数组

传送门 发现这种重复只算一个的题目老是想不出来-- 老套路,先对询问离线,按照右端点从小到大排序.然后我们考虑在右端点右移时新加入的那些位置的贡献,设$pre_i$表示与第$i$个位置相同数字的最后一个位置,那么将第$t$个数字放入的时候,$pre_t$就会产生$1$的贡献,而$pre_{pre_t}$的贡献因为$pre_t$的贡献而变成$0$,可以使用树状数组维护,每一次查询一段区间的贡献和即可. 1 #include<bits/stdc++.h> 2 //This code is writ

HYSBZ 1901 Dynamic Rankings 树状数组套主席树

ZOJ上面这题内存限制太严格,裸的树套树主席树搞法过不去,BZOJ上面这个放的比较松,可以过. 其实就是利用树状数组维护n颗主席树,然后利用前缀和性质求解第k大. #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #include <vector> #include <string> #include

HH的项链 HYSBZ - 1878 (莫队/ 树状数组)

HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一 段贝壳,思考它们所表达的含义.HH不断地收集新的贝壳,因此他的项链变得越来越长.有一天,他突然提出了一 个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答...因为项链实在是太长了.于是,他只 好求助睿智的你,来解决这个问题. Input 第一行:一个整数N,表示项链的长度. 第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数). 第三行:一个整数

树状数组(二)与poj2155 - matrix

今天下午,我进行了树状数组的进一步学习[1],并完成了poj2155的编程与调试,下面是一些记录与感想. 这道题目是一道二维树状数组的练习,中心思想如下: 1.C(x1, y1)(x2, y2)可以用c[x1][y1]++.c[x2 + 1][y1]++.c[x1][y1 + 1]--.c[x2 + 1][y2 + 1]--进行记录(证明与推理过程在注释[1]中). 2.Q(x, y)利用二维树状数组对c[1][1]到c[x][y]的累加和%2(即mod 2)求得(请各位参看注释[1]的资料自行

CodeForces 540E - Infinite Inversions(离散化+树状数组)

花了近5个小时,改的乱七八糟,终于A了. 一个无限数列,1,2,3,4,...,n....,给n个数对<i,j>把数列的i,j两个元素做交换.求交换后数列的逆序对数. 很容易想到离散化+树状数组,但是发现那些没有交换的数也会产生逆序对数,但我没有算. 经明神提示, 把没有用到的数字段化成点.然后用树状数组算一下就好了. 然后我用一个数组记录每个点的长度.比如 <1,2><5,6>,1,2,3,4,5,6只有1,2,5,6用到了,那么离散化为1,2,3,4,5,f[1]=