BZOJ2120 数颜色(树套树)
B. 数颜色
题目描述
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令:
1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。
2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?
输入格式
第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。
第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。
第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。
输出格式
对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。
样例
样例输入
6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
样例输出
4
4
3
4
数据范围与提示
对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过106。。 2016.3.2新加数据两组by Nano_Ape
这个玩意拖了一周了…今天把它补上(主要是因为AC自动机卡住了)。
网上用莫队和分块的比较多,然而我都不会……所以就用数据结构写了,其实就是待修改的主席树。
先预处理出 prei 表示位置 i 前第一个和位置 i 颜色相同的位置(map实现),则区间 [L, R] 里有多少不同的数就转化为了求区间 [L, R] 里prei < L 的位置个数,对 pre 数组建主席树(权值线段树),差不多和板子 一样,只是询问要稍微改一下:
inline int ask(int u,int v,int a,int b,int l,int r,int k)
{
if(l==r)return ;
int lm=sum(l(b))+Sum(,v)-sum(l(a))-Sum(,u),
mid=(l+r)>>;
if(k<=mid)
{
for(int i=u;i>=;i-=lowbit(i))
use[][i]=l(use[][i]);
for(int i=v;i>=;i-=lowbit(i))
use[][i]=l(use[][i]);
return ask(u,v,l(a),l(b),l,mid,k);
}
else
{
for(int i=u;i>=;i-=lowbit(i))
use[][i]=r(use[][i]);
for(int i=v;i>=;i-=lowbit(i))
use[][i]=r(use[][i]);
return lm+ask(u,v,r(a),r(b),mid+,r,k);
}
}
对于修改,首先想到的是直接重新计算pre数组更新,但是复杂度太大肯定会超时,但是真的每个位置的pre值都会改变吗?其实若将i位置修改,最多改变三个pre:
1.i本身。
2.i之后pre=i的位置,最多一个。
3.i之后pre<i,但是值与更改后数值相等的,最多一个。
这样复杂度就可以接受了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
struct node
{
int l,r,sum;
#define l(x) tr[x].l
#define r(x) tr[x].r
#define sum(x) tr[x].sum
}tr[];
int cnt,m,T[],S[],use[][];
int n,Q,a[],pre[];
map<int,int> mp; inline int read()
{
int s=;char a=getchar();
while(a<''||a>'')a=getchar();
while(a>=''&&a<=''){s=s*+a-'';a=getchar();}
return s;
}
inline int lowbit(int x){return x&(-x);}
inline int build(int l,int r)
{
int now=++cnt;
if(l==r)return now;
int mid=(l+r)>>;
l(now)=build(l,mid);
r(now)=build(mid+,r);
return now;
}
inline int build_new(int flag,int mark,int loc,int val)
{
int rt=++cnt;
int before;
if(mark==)before=T[];
else before=flag?T[mark-]:S[mark-];
if(!flag && val)before=S[mark];
sum(rt)=sum(before)+val;
int l=,r=n+,mid,now=rt,still=before;
for(;l(still)||r(still);)
{
mid=(l+r)>>;
if(loc>mid)
{
l(now)=l(still),r(now)=++cnt;
sum(cnt)=sum(r(still))+val;
now=cnt;still=r(still);
l=mid+;
}
else
{
r(now)=r(still),l(now)=++cnt;
sum(cnt)=sum(l(still))+val;
now=cnt;still=l(still);
r=mid;
}
}
return rt;
}
inline int Sum(int y,int x)
{
int res=;
for(int i=x;i>=;i-=lowbit(i))
res+=sum(l(use[y][i]));
return res;
}
inline void updata(int loc,int num)
{
for(int i=loc;i<=n+;i+=lowbit(i))
S[i]=build_new(,i,pre[loc],-);
for(int i=loc;i<=n+;i+=lowbit(i))
S[i]=build_new(,i,num,);
pre[loc]=num;
}
inline int ask(int u,int v,int a,int b,int l,int r,int k)
{
if(l==r)return ;
int lm=sum(l(b))+Sum(,v)-sum(l(a))-Sum(,u),
mid=(l+r)>>;
if(k<=mid)
{
for(int i=u;i>=;i-=lowbit(i))
use[][i]=l(use[][i]);
for(int i=v;i>=;i-=lowbit(i))
use[][i]=l(use[][i]);
return ask(u,v,l(a),l(b),l,mid,k);
}
else
{
for(int i=u;i>=;i-=lowbit(i))
use[][i]=r(use[][i]);
for(int i=v;i>=;i-=lowbit(i))
use[][i]=r(use[][i]);
return lm+ask(u,v,r(a),r(b),mid+,r,k);
}
}
signed main()
{
// freopen("in.txt","r",stdin); n=read(),Q=read();
for(int i=;i<=n;i++)
a[i]=read(),pre[i]=mp[a[i]]+,mp[a[i]]=i;
T[]=build(,n+);
for(int i=;i<=n;i++)
T[i]=build_new(,i,pre[i],);
for(int i=;i<=n;i++)
S[i]=build_new(,i,,);
char ta;int L,R;
for(int i=;i<=Q;i++)
{
cin>>ta;
L=read(),R=read();
if(ta=='Q')
{
for(int j=L-;j>=;j-=lowbit(j))
use[][j]=S[j];
for(int j=R;j>=;j-=lowbit(j))
use[][j]=S[j];
printf("%ld\n",ask(L-,R,T[L-],T[R],,n+,L+));
}
else
{
int tem=pre[L];
updata(L,);
a[L]=R;
for(int j=;j<=n;j++)
{
if(a[j]==R && j<L)
updata(L,j+);
if(pre[j]==L+)
updata(j,tem);
if(a[j]==R && j>L && pre[j]-<L)
updata(j,L+);
}
}
}
}
BZOJ2120 数颜色(树套树)的更多相关文章
- 「洛谷1903」「BZOJ2120」「国家集训队」数颜色【带修莫队,树套树】
题目链接 [BZOJ传送门] [洛谷传送门] 题目大意 单点修改,区间查询有多少种数字. 解法1--树套树 可以直接暴力树套树,我比较懒,不想写. 稍微口胡一下,可以直接来一个树状数组套主席树,也就是 ...
- NOI模拟 颜色 - 带修莫队/树套树
题意: 一个颜色序列,\(a_1, a_2, ...a_i\)表示第i个的颜色,给出每种颜色的美丽度\(w_i\),定义一段颜色的美丽值为该段颜色的美丽值之和(重复的只计算一次),每次都会修改某个位置 ...
- 树套树Day1线段树套平衡树bzoj3196
您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查 ...
- 【BZOJ3262】陌上花开(树套树)
[BZOJ3262]陌上花开(树套树) 题面 对于权限题,我这种苦逼肯定是从别的OJ上搞的对不对??? CJOJ 洛谷 Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味 ...
- BZOJ 3110: [Zjoi2013]K大数查询 [树套树]
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6050 Solved: 2007[Submit][Sta ...
- bzoj3295: [Cqoi2011]动态逆序对(树套树)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...
- BZOJ 3110 k大数查询 & 树套树
题意: 有n个位置,每个位置可以看做一个集合,现在要求你实现一个数据结构支持以下功能: 1:在a-b的集合中插入一个数 2:询问a-b集合中所有元素的第k大. SOL: 调得火大! 李建说数据结构题能 ...
- 【BZOJ】1901: Zju2112 Dynamic Rankings(区间第k小+树套树)
http://www.lydsy.com/JudgeOnline/problem.php?id=1901 这题调了我相当长的时间,1wa1a,我是第一次写树套树,这个是树状数组套splay,在每个区间 ...
- Uva 3767 Dynamic len(set(a[L:R])) 树套树
Dynamic len(set(a[L:R])) Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 https://uva.onlinejudge.org/in ...
- 树套树专题——bzoj 3110: [Zjoi2013] K大数查询 & 3236 [Ahoi2013] 作业 题解
[原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 978 Solved: 476 Descri ...
随机推荐
- shell脚本只提供整数算术运算(三种方式)—((表达式))、let "表达式"、value=`expr 表达式右边` (转载)
转自:http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201131055455754/ 数值运算: 在bash中只提供了整数运算,一 ...
- 深度解密Go语言之 map
目录 什么是 map 为什么要用 map map 的底层如何实现 map 内存模型 创建 map 哈希函数 key 定位过程 map 的两种 get 操作 如何进行扩容 map 的遍历 map 的赋值 ...
- hdoj3665【简单DFS】
题意: 略. 思路: n就10而已,没有环,搜一下就好了.. #include <bits/stdc++.h> using namespace std; typedef long long ...
- P4692 [Ynoi2016]谁的梦
传送门 分别考虑每一种颜色对答案的贡献.每种颜色的贡献就是他出现的区间个数,那么可以用总区间减去不包含它的区间个数,把每一个序列里不包含它的区间个数加起来,然后不同序列用乘法原理计算即可 于是我辛辛苦 ...
- hdu 4704 Sum【组合数学/费马小定理/大数取模】By cellur925
首先,我们珂以抽象出S函数的模型:把n拆成k个正整数,有多少种方案? 答案是C(n-1,k-1). 然后发现我们要求的是一段连续的函数值,仔细思考,并根据组合数的性质,我们珂以发现实际上答案就是在让求 ...
- Educational Codeforces Round 20 A
Description You are given matrix with n rows and n columns filled with zeroes. You should put k ones ...
- BFS 2015百度之星初赛2 HDOJ 5254 棋盘占领
题目传送门 /* BFS:先把1的入队,每个1和它相邻的组合后看看能不能使0变1,若有则添加入队,change函数返回改变了多少个0 注意:结果还要加上原来占领的 */ #include <cs ...
- POJ 1692 Crossed Matchings dp[][] 比较有意思的dp
http://poj.org/problem?id=1692 这题看完题后就觉得我肯定不会的了,但是题解却很好理解.- - ,做题阴影吗 所以我还是需要多思考. 题目是给定两个数组,要求找出最大匹配数 ...
- HDU 2828 Lamp 二分图的最大匹配 模型题
http://acm.hdu.edu.cn/showproblem.php?pid=2828 给定n个灯,m个开关,使得每栈灯亮,前提是控制这栈灯的开关的状态是其中一个.(题目应该都看得懂) 其实我想 ...
- Java 学习列表
这是从450家企业的招聘信息中统计而来,相对来说还是比较真实的,虽然有些公司的招聘要求万年不变,但还是可以大致反应企业的招聘要求的.