• luoguP1972 [SDOI2009]HH的项链


    经典颜色问题推荐博文

    https://www.cnblogs.com/tyner/p/11519506.html

    https://www.cnblogs.com/tyner/p/11616770.html

    https://www.cnblogs.com/tyner/p/11620894.html

    题意

    求一段区间中的元素种类, 同一个元素可能有多个,但是只记
    一次, 多组询问
    长度 <= 1000000, 询问次数 <= 200000

    记得写快读

    分析

    重复颜色, 套路题

    处理nxt, 枚举左端点,考虑''移动左端点''这一操作对区间答案的影响

    具体做法来自: 150137

    没有修改,我们不妨离线
    我们将询问按照左端点排序, 然后维护一个当前的左指针和询问的左指针, 再维护一个 next 数组表示该物品的下一个相同元素物品的位置
    维护一个 ans 数组, 每次当 l < ql 的时候, 更新 nextl, 然后 l 前
    移继续即可,询问就是求前缀和啦

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define lowbit(x) (x&-x)
    inline int read() {
        char ch = getchar(); int f = 1, x = 0;
        while(ch<'0' || ch>'9') {if(ch == '-') f = -1; ch = getchar();} 
        while(ch>='0' && ch<='9') {x = x*10+ch-'0'; ch = getchar();}
        return x*f;
    }
    const int MAX = 1000000+99;
    
    int n, m, max_;
    int arr[MAX], nxt[MAX], lst[MAX];
    int t[MAX];
    struct node{
        int l, r;
        int ans, id;
    }cmd[MAX];
    bool cmp1(node a, node bb) {
    	return a.l < bb.l;
    }
    bool cmp2(node a, node bb) {
    	return a.id < bb.id;
    }
     
    void add(int x, int k) {
        while(x <= n) {t[x] += k; x += lowbit(x);} 
    }
    int query(int x) {
        int res = 0;
        while(x) {res += t[x]; x -= lowbit(x);}
        return res;
    }
    
    void pre() {
        n = read();
        for(int i = 1; i <= n; i++) arr[i] = read(), max_ = max(max_, arr[i]);
        for(int i = n; i >= 1; i--) {//颜色问题--处理nxt[] 
            nxt[i] = lst[arr[i]];
            lst[arr[i]] = i;
        }
    //	for(int i = 1; i <= n; i++) printf("%d %d
    ", nxt[i], lst[i]);
        for(int i = 1; i <= max_; i++) if(lst[i]) add(lst[i], 1);//初始化l==1的状态(注意判颜色是否存在
    	// 注意lst的下标是颜色,保存的是每个颜色第一次出现的位置坐标,所以是<=max_ 
        m = read();
        for(int i = 1; i <= m; i++) cmd[i].id = i,cmd[i].l = read(), cmd[i].r = read();
        sort(cmd+1, cmd+1+m, cmp1);//按 l 从小到大排序 
    }
    
    void solve() {
    	int pos = 1;
        for(int l = 1; l <= n; l++) {//枚举左端点 
    		while(l == cmd[pos].l) {
    			cmd[pos].ans = query(cmd[pos].r);
    			++pos;
    		}
    		add(l, -1);
    		if(nxt[l]) add(nxt[l], 1);
        }
        
        sort(cmd+1, cmd+1+m, cmp2);
        for(int i = 1; i <= m; i++) printf("%d
    ", cmd[i].ans);
    }
    
    int main() {
        pre();
    	solve();    
    	return 0;
    }
    
  • 相关阅读:
    数位dp模板
    HDU
    hdu 2586 How far away ? ( 离线 LCA , tarjan )
    POJ 1655 Balancing Act( 树的重心 )
    HDU 2196 Computer( 树上节点的最远距离 )
    HDU 5266 pog loves szh III ( LCA + SegTree||RMQ )
    HDU 5265 pog loves szh II
    2015区域赛起航
    2015GDCPC广东省赛总结
    SGU 521 North-East ( 二维LIS 线段树优化 )
  • 原文地址:https://www.cnblogs.com/tyner/p/11616770.html
Copyright © 2020-2023  润新知