天天看點

Turing Tree +HDU-3333+離散化處理+離線化處理思路+樹狀數組

題目連結

題目資料:
T (1 ≤ T ≤ 10),(1 ≤ N ≤ 30,000),(0 ≤ Ai ≤ 1,000,000,000)
Q (1 ≤ Q ≤ 100,000)
題目限制:
Time limit:   3000 ms
Memory limit: 32768 kB
           
題目大意:
統計一個區間内不重複的資料和。
例如 :
1 1 2 1 3
3
1 5  (1+2+3)
2 4  (1+2)
3 5  (2+1+3)
           
*解決方法:離線處理。(不了解的可以去百度,我也不是和了解,這算是離線處理的第一道題)
(我盡量把我了解的離散處理說一下)
*解決思路:
資料這麼大,當然離散化,若不離散化,1e9咋建樹;
序列如此多,當然離線化,若不離線化,1e5怎查詢;
如何離散化,請看我代碼,如何離線化,右點小在前。
(言歸正傳了哈哈哈哈哈哈哈)
第一步:離散化。離散化還不會的,看下面代碼。下面說離線化的思路:
第二步:離線化:
#1,排序:
對:
1 5 
2 4 
3 5
按照右端點進行排序,右端點小的在前,對左端點不要求;
排序後:
2 4  (1)
1 5  (2)
3 5  (3)
#2,建樹:樹的葉子節點表示資料最新一次出現的位置,記錄的是目前位置資料的大小。(1 1 2 1 3)
樹的葉子節點:  1 2 3 4 5
記錄的資訊:    0 0 0 0 0 (建樹時還沒加入任何節點)
1&插入 1:更新樹的資訊:
樹的葉子節點:  1 2 3 4 5
記錄的資訊:    1 0 0 0 0 (插入1,1最新的一次位置為1)
2&插入 1:更新樹的資訊:
樹的葉子節點:  1 2 3 4 5
記錄的資訊:    0 1 0 0 0 (插入1,1最新的一次位置為2,并抹除上一次出現的位置)
3&插入 2:更新樹的資訊:
樹的葉子節點:  1 2 3 4 5
記錄的資訊:    0 1 2 0 0 (插入2,2最新的一次位置為3,第一次出現)
4&插入 1:更新樹的資訊:
樹的葉子節點:  1 2 3 4 5
記錄的資訊:    0 0 2 1 0 (插入1,1最新的一次位置為4,并抹除上一次出現的位置)
(這時剛好遇到排序後的第一個序列,[2,4],統計2到4的和)
5&插入 3:更新樹的資訊:
樹的葉子節點:  1 2 3 4 5
記錄的資訊:    0 0 2 1 3 
(統計[1,5],[3,5]的區間和)
(看到這裡你可能會想,為啥要這樣處理呢?)
第一點:所有的點直插入了一次,如果對每個序列都單獨建一次樹的話,you can try。
第二點: 為什木要對序列按右端點小的排序呢?給一個組資料:
1 3 1 2 5
1 3
1 2
按照上面建樹的過程模拟一下,看不排序直接建樹,會有什麼結果。
           

《樹狀數組建樹》《代碼是我的,不能拿走,上面解題思路是大家的》

《QQ:3237676809,一起在ACM的小路上高歌啊~~~~》

// T (1 ≤ T ≤ 10),(1 ≤ N ≤ 30,000),(0 ≤ Ai ≤ 1,000,000,000)
//Q (1 ≤ Q ≤ 100,000)
#include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=30010;
const int M=100010;
LL a[30010],a2[30010];
struct point
{
	int L,R,id;
}b[M];
LL  ans[M];
LL  c[N];
int vis[N];

int n,len;
// 1 
void int_i(void)
{
	len=0;
	for(int i=1;i<=n;i++)
	{
		c[i]=0;
		vis[i]=0;
	}
	return ;
}
// 2
int cmp_b(point s1,point s2)
{
	return s1.R < s2.R;
}
// 3
int lowbit(int x)
{
	return x&(-x);
}
// 4
void update_tree(int pos,LL x)
{
	while(pos<=n)
	{
		c[pos]+=x;
		pos+=lowbit(pos);
	}
	return ;
}
// 5
LL getsum(int pos)
{
	LL ans=0;
	while(pos>0)
	{
		ans+=c[pos];
		pos-=lowbit(pos);
	}
	return ans;
}
// 6 
void simplify(void)
{
	sort(a2+1,a2+1+n);
    len=unique(a2+1,a2+n+1) - (a2+1);
	for(int i=1;i<=n;i++)
	{
		int pos=lower_bound(a2+1,a2+n+1,a[i]) - a2;
		a[i]=pos;
	}
	return ;
}
int main()
{
	int t,m;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		int_i();
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&a[i]);
			a2[i]=a[i];
		}
		scanf("%d",&m);
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d",&b[i].L,&b[i].R);
			b[i].id=i;
		}
		sort(b+1,b+m+1,cmp_b);
		simplify();
		int j=1; 
		for(int i=1;i<=m;i++)
		{
			while(j<=b[i].R)
			{
				if(vis[a[j]]!=0)
				{
					update_tree(vis[a[j]],-a2[a[j]]);
				}
				vis[a[j]]=j;
				update_tree(j,a2[a[j]]);
				j++;
			}
			ans[b[i].id]=getsum(b[i].R)-getsum(b[i].L-1);
		}
		
		for(int i=1;i<=m;i++)
		{
			printf("%lld\n",ans[i]);
		}
	}
	return 0;
}