zoukankan      html  css  js  c++  java
  • 利用主席树 搞区间不同值的和

    #include<iostream>
    #include<vector>
    #include<cstdio>
    #include<map>
    #include<algorithm> 
    using namespace std;
    typedef long long ll;
    const int Maxn = 1e5 + 6;
    struct Node {
    	int l;
    	int r;
    	ll val;
    
    }T[Maxn * 40];
    
    int root[Maxn];
    ll arr[Maxn];
    
    vector<int>v;
    int n, m;
    int cnt = 0;
    
    int built(int &node, int l, int r) {
    	node = ++cnt;
    	T[node].val = 0;
    	if (l == r) return 0;
    	int mid = (l + r) / 2;
    	built(T[node].l, l, mid);
    	built(T[node].r, mid + 1, r);
    	
    }
    int update(int &node,int last,int be,int en,int i,ll val) {
    	T[++cnt] = T[last];	//复制一个单独的节点
    	node = cnt;//***接上节点,十分重要
    	if (be == en) {
    		T[node].val = val;
    		return T[node].val;
    	}
    	int mid = (be + en) / 2;
    	if (i <= mid) update(T[node].l, T[last].l, be, mid, i, val);
    	else update(T[node].r, T[last].r, mid + 1, en, i, val);
    	T[node].val = T[T[node].l].val + T[T[node].r].val;
    	return T[node].val;
    }
    
    ll query(int node,int be, int en, int LL, int RR) {//当前节点node  l--r,当前区间,,,x--y,所求区间
    	if (LL <= be && en <= RR) {
    		return T[node].val;
    	}
    	int mid = (be + en) / 2;
    	ll res = 0;
    	if(mid >= LL) res += query(T[node].l, be, mid, LL, RR);
    	if(RR > mid)  res+= query(T[node].r, mid + 1, en, LL, RR);
    	return res;
    }
    int t;
    
    
    map<ll, int>ins;
    int main() {
    	scanf("%d", &t);
    	while (t--) {
    		ins.clear();
    		cnt = 0;
    		scanf("%d", &n);
    		for (int i = 1; i <= n; i++) {
    			scanf("%lld", &arr[i]);
    		}
    		built(root[0], 1, n);
    		for (int i = 1; i <= n; i++) {
    			//没出现就直接加上
    			if (ins[arr[i]] == 0) {
    				update(root[i], root[i - 1], 1, n, i, arr[i]);
    				ins[arr[i]] = i;
    			}
    			else {
    				int tmp = 0;//tmp只是一个中介,就像交换数时候的 t 一样
    				update(tmp, root[i - 1], 1, n, ins[arr[i]], 0);
    				update(root[i], tmp, 1, n, i, arr[i]);
    				ins[arr[i]] = i;
    			}
    		}
    		scanf("%d", &m);
    
    		for (int i = 0; i < m; i++) {
    			int x, y;
    			scanf("%d%d", &x, &y);
    			ll ans = query(root[y], 1, n, x, y);
    			printf("%lld
    ",ans);
    
    		}
    	}
    	return 0;
    }
    

      

    https://blog.csdn.net/why932346109/article/details/98955619

    这个大佬写的十分详细,我留下了以后准备着复习看吧

    画图之后就理解了,太强了!!!

    题意:给你一个长度为n的序列,m个询问:询问区间[L,R]中不同的数的和是多少?

    大概就是这样,最后附上新垣结衣

    寻找真正的热爱
  • 相关阅读:
    Linux命令:sed -i 解析、sed是什么、工作原理、基本语法使用、数字和正则定址、基本子命令以及最常用子命令 s 的用法
    【转】putty里面的连接key文件(ppk文件)转换为xshell里面使用的key文件
    【转】Go 中如何优雅关闭子进程?
    [转]golang 获取本机真实IP
    【转】prometheus数据写入TDengine
    怎么查看redhat的版本
    【转】YML是什么
    [转]为什么要进行URL编码
    [转]Ubuntu 上 Yarn 安装
    【转】docker -v 和Dockerfile 中VOLUME 区别
  • 原文地址:https://www.cnblogs.com/lesning/p/11385069.html
Copyright © 2011-2022 走看看