• AHOI2013 作业


    第一问就是主席树了。

    依据套路, 对于每个数 x, 记录上一次出现的位置 prex, 于是问题就变成了: 查询区间 [l,r] 内, 值域 [a,b] 内, pre [0,l-1] 内的数, 是个三维的偏序问题。

    看上去一般做法要 O(log3), 但没有修改, 可以可持久化降一维。

    然后剩下的二维问题就树套树解决了。

    当然,开玩笑的, 第一维离线降下来就行了。

    #include<bits/stdc++.h>
    #define INF 2147483647
    using namespace std;
    
    const int N = 1e5 + 3, SZ = N*20*2+233;
    
    int n, m, a[N], las[N], pre[N];
    
    struct ques {
    	int l, r, a, b;
    	int ans1, ans2;
    } obj[N];
    
    int ecnt, hd[N], nt[N*2+3], vr[N*2+3];
    void ad(int u, int v) { nt[++ecnt] = hd[u], hd[u] = ecnt; vr[ecnt] = v; }
    
    namespace BIT {
    	int t[N];
    	void ins(int x) {
    		for(; x<=n; x+=(x&(-x))) ++t[x];
    	}
    	int ask_(int x) {
    		int res = 0;
    		for(; x; x-=x&(-x)) res += t[x];
    		return res;
    	}
    	int ask(int l, int r) { return ask_(r) - ask_(l-1); }
    }
    
    int cnt;
    #define newnode(s, v, a, b) (&(*pool[cnt++] = node(s, v, a, b)))
    #define merge(a, b) newnode(a->siz+b->siz, b->val, a, b)
    #define upd(me) if(me->ls->siz) me->siz=me->ls->siz+me->rs->siz, me->val=me->rs->val
    struct node {
    	int siz, val;
    	node *ls, *rs;
    	node(int s, int v, node *a, node *b) : siz(s), val(v), ls(a), rs(b) {
    	}
    	node() {
    	}
    } *root[N], *emp, t[SZ], *pool[SZ];
    
    inline void maintain(node *me) {
    	if(me->ls->siz > me->rs->siz * 4)
    		me->rs = merge(me->ls->rs, me->rs), pool[--cnt] = me->ls, me->ls = me->ls->ls;
    	if(me->rs->siz > me->ls->siz * 4)
    		me->ls = merge(me->ls, me->rs->ls), pool[--cnt] = me->rs, me->rs = me->rs->rs;
    }
    
    void ins(int x, node *me) {
    	if(me->siz == 1)
    		me->ls = newnode(1, min(x, me->val), emp, emp),
    		me->rs = newnode(1, max(x, me->val), emp, emp);
    	else
    		ins(x, x>me->ls->val ? me->rs : me->ls), maintain(me);
    	upd(me);
    }
    
    int low(int x, node *me) {
    	if(me->siz == 1) return (me->val <= x);
    	else return x>=me->ls->val ? me->ls->siz + low(x, me->rs) : low(x, me->ls);
    }
    
    namespace nbBIT {
    	void ins(int x, int v) {
    		for(; x<=n; x+=(x&(-x))) ins(v, root[x]);
    	}
    	int ask_(int x, int v) {
    		int res = 0;
    		for(; x; x-=(x&(-x))) res += low(v, root[x]);
    		return res;
    	}
    	int ask(int l, int r, int v) {
    		return ask_(r, v) - ask_(l-1, v);
    	}
    } 
    
    int main() {
    	emp = new node(0, 0, NULL, NULL);
    	for(int i=0; i<SZ; ++i) pool[i] = &t[i];
    	scanf("%d%d", &n, &m);
    	for(int i=1; i<=n; ++i) root[i] = newnode(1, INF, emp, emp);
    	
    	for(int i=1; i<=n; ++i) {
    		scanf("%d", &a[i]);
    		pre[i] = las[a[i]];
    		las[a[i]] = i;
    	}
    	// May I have your Name ?
    	for(int i=1; i<=m; ++i) {
    		scanf("%d%d%d%d", &obj[i].l, &obj[i].r, &obj[i].a, &obj[i].b);
    		obj[i].ans1 = obj[i].ans2 = 0;
    		if(obj[i].l - 1) ad(obj[i].l - 1, i);
    		ad(obj[i].r, i);
    	}
    	// My name is F#
    	
    	for(int i=1; i<=n; ++i) {
    		BIT::ins(a[i]);
    		nbBIT::ins(a[i], pre[i]);
    //		cout << "# " << pre[i] << '
    ';
    		for(int j = hd[i]; j; j = nt[j]) {
    			int id = vr[j];
    			if(i == obj[id].l-1)
    			{
    				obj[id].ans1 -= BIT::ask(obj[id].a, obj[id].b);
    				obj[id].ans2 -= nbBIT::ask(obj[id].a, obj[id].b, obj[id].l - 1);
    			}
    			if(i == obj[id].r)
    			{
    				obj[id].ans1 += BIT::ask(obj[id].a, obj[id].b);
    				obj[id].ans2 += nbBIT::ask(obj[id].a, obj[id].b, obj[id].l - 1);
    			}
    		}
    	}
    	
    	for(int i=1; i<=m; ++i) cout << obj[i].ans1 << ' ' << obj[i].ans2 << '
    ';
    	
    	return 0;
    }
    
  • 相关阅读:
    hdu 1142 用优先队列实现Dijkstra
    POJ 2063 Investment 完全背包
    POJ 3260 多重背包+完全背包
    bignum 大数模板
    POJ 3468(树状数组的威力)
    POJ 3468 线段树裸题
    hdu 1058 Humble Numbers
    CodeForces 185A 快速幂
    POJ 1990 MooFest 树状数组
    设计模式(20)策略模式
  • 原文地址:https://www.cnblogs.com/tztqwq/p/14310582.html
Copyright © 2020-2023  润新知