【BZOJ2120】数颜色(树套树+set)

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2120

题解:http://blog.sina.com.cn/s/blog_6e63f59e0101bm87.html

一开始懒得离散化,跑了7000+ms23333 宛如一个智障,可是出现了这么迷醉的情况、

2333果然还是要勤快一点 写个离散化啊

#include <set>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define MaxN 20010
#define MaxM 7000010
using namespace std;
int n, S = 0, m, tot = 0, N = 0;
int num[MaxN], da[MaxN], map[MaxN];
int root[MaxN], t1[MaxN], t2[MaxN];
int ls[MaxM], rs[MaxM], sum[MaxM];
char s[10];
set <int> q[MaxN];
struct rec{
    int l, r;
    char s[10];
}op[MaxN];
void Read_Data(){
    scanf("%d%d", &n, &m);
    for (int i = 0; i < MaxN; i++) q[i].insert(n+1), q[i].insert(0);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &num[i]);
        da[++tot] = num[i];
    }
    for (int i = 1; i <= m; i++){
        scanf("%s%d%d", op[i].s, &op[i].l, &op[i].r);
        if (op[i].s[0] != ‘Q‘) da[++tot] = op[i].r;
    }
    sort(da+1, da+1+tot);
    map[++N] = da[1];
    for (int i = 2; i <= tot; i++)
        if (da[i] != da[i-1]) map[++N] = da[i];
}

int find(int x){
    int l = 1, r = N, mid;
    while (l < r) {
        mid = (l+r) >> 1;
        if (x <= map[mid]) r = mid;
        else l = mid+1;
    }
    return l;
}

void updata(int &x, int l, int r, int k, int c){
    int fa = x;
    if (!x) x = ++S;
    ls[x] = ls[fa], rs[x] = rs[fa], sum[x] = sum[fa]+c;
    if (l == r) return;
    int mid = (l+r) >> 1;
    if (k <= mid) updata(ls[x], l, mid, k, c);
    else updata(rs[x], mid+1, r, k, c);
}

int lowbit(int x) {
    return x & (-x);
}

void updata(int x, int k, int c){
    for (int i = x; i <= n; i += lowbit(i)) updata(root[i], 0, n, k, c);
}

int query(int a, int b, int k){
    int l = 0, r = n, mid, ret = 0, len1 = 0, len2 = 0, t = 0;
    for (int i = a; i; i -= lowbit(i)) t1[++len1] = root[i];
    for (int i = b; i; i -= lowbit(i)) t2[++len2] = root[i];
    while (l < r){
        mid = (l+r) >> 1;
//        cout<<a<<" "<<b<<" t"<<b-a<<" l"<<l<<" r"<<r<<endl;
        if (k <= mid) {
            r = mid;
            for (int i = 1; i <= len1; i++) ret -= sum[rs[t1[i]]];
            for (int i = 1; i <= len2; i++) ret += sum[rs[t2[i]]];
            for (int i = 1; i <= len1; i++) t1[i] = ls[t1[i]];
            for (int i = 1; i <= len2; i++) t2[i] = ls[t2[i]];
        }
        else {
            l = mid+1;
            for (int i = 1; i <= len1; i++) t1[i] = rs[t1[i]];
            for (int i = 1; i <= len2; i++) t2[i] = rs[t2[i]];
        }
    }
    return ret;
}

void Solve(){
    int l, r, c;
    n++;
    for (int i = 1; i < n; i++) num[i] = find(num[i]), q[num[i]].insert(i);
    for (int i = 1; i < n; i++) updata(i, *q[num[i]].upper_bound(i), 1);//, updata(0, i, 1);
//    cout<<query(1, 6, 6);
    for (int i = 1; i <= m; i++){
        int l = op[i].l, r = op[i].r;
        if (op[i].s[0] == ‘Q‘){
            printf("%d\n", query(l-1, r, r));
        }
        else {
            set<int>::iterator p;
            p = q[num[l]].lower_bound(l); p--;
            int t = *(p);
            if (t) {
                updata(t, l, -1);
                updata(t, *q[num[l]].upper_bound(l), 1);
            }
            updata(l, *q[num[l]].upper_bound(l), -1);
            q[num[l]].erase(l);
            num[l] = find(op[i].r);
            q[num[l]].insert(l);
            p = q[num[l]].lower_bound(l); p--;
            t = *(p);
            if (t) {
                updata(t, l, 1);
                updata(t, *q[num[l]].upper_bound(l), -1);
            }
            updata(l, *q[num[l]].upper_bound(l), 1);
        }
    }
}

int main(){
    Read_Data();
    Solve();
    return 0;
}
时间: 2024-08-04 00:48:48

【BZOJ2120】数颜色(树套树+set)的相关文章

BZOJ_3196_二逼平衡树(树套树:线段树+Treap)

描述 可以处理区间问题的平衡树. 分析 树套树.可以用线段树套Treap.人生第一道树套树的题... op1:如果在整区间,直接在该区间的treap上求解.否则分两个区间求解,然后相加.最后+1. op2:这个不太好直接做,可以二分,每次假定一个值,用这个值去做op1,以此求得一个rank=k+1的数,求rank=k的数等价与求这个数的前驱pre. op3:先删后加. op4&op5:如果在整区间,直接在该区间的treap上求解,否则分量个区间求解,pre取最大值,suc取最小值.注意有些数在有

BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

[BZOJ3110] [Zjoi2013] K大数查询 (树套树)

Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M 接下来M行,每行形如1 a b c或2 a b c Output 输出每个询问的结果 Sample Input 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 Sample Output 1 2 1 HINT [

bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)

Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的个数. Sample Input 5 4 1 5 3

BZOJ3295 动态逆序对 树套树, 树状数组套线段树(主席树)

Orz黄学长,蒟蒻在黄学长的带领下,通过阅读黄学长的代码!终于会了这道题! 首先我想先说一下这道题的思路(准确来说是黄学长的). 很明显,树状数组应该不用讲吧!关键是内存怎么开,维护一些什么样的数据? 其实我们通过观察,很快可以发现,你维护被删的数比维护所有的数轻松多了(不管是空间上,还是时间上).所以我们就可以从这方面想!(其实我一开始的思路,因为这道题我已经看过很久了,一直想写,毕竟是白书里面的一道例题嘛!一开始,蒟蒻的我是打算这样的用树状数组套权值线段树,并且是维护所有的数,我发现空间不够

bzoj 1901: Zju2112 Dynamic Rankings(树套树)

1901: Zju2112 Dynamic Rankings 经典的带修改求区间第k小值问题 树套树模板,我是用的线段树套splay实现的,而且用的数组模拟的,所以可能空间略大,bzoj过了,zoj过不了. 思路很简单,用线段树维护区间,用splay维护区间内的权值,然后询问的时候,二分答案key,然后在区间内找小于key的数有多少个. 贴上模板: #include<stdio.h> #include<string.h> #include<algorithm> #def

[树套树]K大数查询

有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少.为了强制在线,每一次的a,b是加密的,需要异或lastans的后8位进行解密,其中lastans为上次输出的结果,初始为零.如果解密后a>b则先交换a,b数据保证解密后a,b不会超过N如果解密后a,b出现0,则赋值为1. 来历:bzoj上的一道题,经过子祯学长的魔改后,数据范围变得很奇怪... 算法:树

ZOJ 2112 Dynamic Rankings(主席树套树状数组+静态主席树)

题意:给定一个区间,求这个区间第k大的数,支持单点修改. 思路:主席树真是个神奇的东西.........速度很快但是也有一个问题就是占用内存的很大,一般来说支持单点修改的主席树套树状数组空间复杂度为O(n*logn*logn), 如果查询较少的话,可以初始的时候用一颗静态主席树,这样空间复杂度可以降为O(n*logn+q*logn*logn),勉强可以过zoj这道题. 这道题看了好久好久才懂...网上题解一般就几句话.......下面是自己的一些理解. 首先静态主席树这个东西其实比较好懂,就是对

BZOJ4553: [Tjoi2016&amp;Heoi2016]序列 树套树优化DP

把pos[i]上出现的平常值定义为nor[i]最大值定义为max[i]最小值定义为min[i],那么我们发现在两个值,i(前),j(后),当且仅当max[i]<=nor[j],nor[i]<=min[j]时才会组成序列的前后两个值,并且当序列里所有连续的两个值都满足这个条件是时就可以,因此我们以f[i]表示以i为起点的序列最长值,那么我们就可以转移了f[i]=maxf[j](max[i]<=nor[j],nor[i]<=min[j],pos[i]<pos[j])+1,这就是一

树套树【bzoj3262】陌上花开

/* [bzoj3262]陌上花开 2014年6月19日1,2430 Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb.显然,两朵花可能有同样的属性.需要统计出评出每个等级的花的数量. Input 第一行为N,K (1 <= N <= 100,000, 1 <= K <