• HDU 3333 Turing Tree(树状数组/主席树)


    题意

    给定一个长度为 (n​) 的序列,(m​) 个查询,每次查询区间 ([L,R]​) 范围内不同元素的和。

    (1leq T leq 10)

    (1 leq nleq 30000)

    (1leq mleq 100000)

    思路

    这道题没有强制在线,又没有修改,离线会比在线好想。

    可以从第 (1) 个数到第 (n) 个数一次添加,并去除之前的相同元素,以此为顺序。就是说对于 (m) 个询问,按右端点进行排序,以此添加进每个数字并只保留最右端的数,借助 ( ext{map}) 去重,区间和用树状数组维护。

    假如要强制在线,该怎么办呢?

    假如我们能力开下 (n) 个树状数组,就可以在线的查询了,可是 (n) 个树状数组肯定开不下,那动态开点线段树?可以,但是每次也是要把原来的线段树复制一遍,复杂度一累,时间过不去。
    主席树的作用就体现出来了,回顾离线的写法,每次只会修改 (1-2) 个位置,那在前缀的基础上,保留原来的历史版本不就行了?这就是可持久化,详见代码。

    代码

    #include<bits/stdc++.h>
    #define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
    #define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
    typedef long long LL;
    using namespace std;
    const int N=3e5+5;
    const int NN=1e7+2e6+5;
    
    struct ChairmanTree
    {
    	int lson[NN],rson[NN];LL sum[NN];
    	int rt[N],tot;
    	int &operator [](const int x){return rt[x];}
    	void build()
    	{
    		memset(rt,0,sizeof(rt));
    		sum[tot=0]=lson[0]=rson[0]=0;
    	}
    	void create(int &k){sum[++tot]=sum[k],lson[tot]=lson[k],rson[tot]=rson[k],k=tot;}
    	void update(int &k,int x,int val,int l,int r)
    	{
    		create(k);
    		if(l==r)
    		{
    			sum[k]+=val;
    			return;
    		}
    		int mid=(l+r)>>1;
    		if(x<=mid)update(lson[k],x,val,l,mid);
    		else update(rson[k],x,val,mid+1,r);
    		sum[k]=sum[lson[k]]+sum[rson[k]];
    	}
    	LL query(int k,int L,int R,int l,int r)
    	{
    		if(!k)return 0;
    		if(L<=l&&r<=R)return sum[k];
    		int mid=(l+r)>>1;
    		if(R<=mid)return query(lson[k],L,R,l,mid);
    		else if(L>mid)return query(rson[k],L,R,mid+1,r);
    		else return query(lson[k],L,R,l,mid)+query(rson[k],L,R,mid+1,r);
    	}
    }CT;
    map<int,int>mp;
    
    int main()
    {
    	int T,n,m;
    	scanf("%d",&T);
    	while(T--)
    	{
    		mp.clear();
    		scanf("%d",&n);
    		CT.build();
    		FOR(i,1,n)
    		{
    			int x;
    			scanf("%d",&x);
    			CT[i]=CT[i-1];
    			if(mp[x])CT.update(CT[i],mp[x],-x,1,n);
    			CT.update(CT[i],i,x,1,n);
    			mp[x]=i;
    		}
    		scanf("%d",&m);
    		while(m--)
    		{
    			int x,y;
    			scanf("%d%d",&x,&y);
    			printf("%lld
    ",CT.query(CT[y],x,y,1,n));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    【Linux_Unix系统编程】Chapter4 文件IO
    【Unix网络编程】chapter6 IO复用:select和poll函数
    【Unix网络编程】 chapter5 TCP客户,服务器程序实例
    【Unix网络编程】chapter3 套接字编程简介
    VS自动编译脚本
    【Python编程:从入门到实践】chapter4 操作列表
    【Python编程:从入门到实践】chapter3 列表简介
    【Python编程:从入门到实践】chapter2 变量和简单数据类型
    【Unix网络编程】chapter2传输层:TCP,UDP和SCTP
    vim配置编辑php
  • 原文地址:https://www.cnblogs.com/Paulliant/p/10144336.html
Copyright © 2020-2023  润新知