日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

SPOJ 3267: DQUERY 树状数组,离线算法

發(fā)布時(shí)間:2024/4/17 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SPOJ 3267: DQUERY 树状数组,离线算法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

給出q個(gè)詢問,詢問一段區(qū)間里面的不同元素的個(gè)數(shù)有多少個(gè)。

離線做,用樹狀數(shù)組。

設(shè)樹狀數(shù)組的意義是:1--pos這個(gè)段區(qū)間的不用元素的種類數(shù)。怎么做?就是add(pos,1);在這個(gè)位置中+1,就是說這個(gè)位置上元素種類+1。

然后先把詢問按R遞增的順序排序。因?yàn)檫@里是最優(yōu)的,我每次盡量往R靠,使得查詢不重不漏。

什么意思呢?

就是假如有:2、1、3、5、1、7的話。

一開始的[1,4]這段數(shù)字全部壓進(jìn)樹狀數(shù)組,用個(gè)數(shù)組book[val],表示val這個(gè)元素出現(xiàn)的最右的位置,因?yàn)槲覀冃枰獎(jiǎng)h除重復(fù)的,也是要盡量往右靠。到達(dá)pos=5這個(gè)位置的時(shí)候,注意了,因?yàn)?是出現(xiàn)過的book[1] = 2,所以我們要做的是把2這個(gè)位置出現(xiàn)元素的種類數(shù)-1,就是add(book[1],-1)。然后把第五個(gè)位置出現(xiàn)的元素種類數(shù)+1,就是add(5,1)。為什么呢?因?yàn)槟惚M量把種類往右靠,因?yàn)槲覀兊腞是遞增的,這樣,你使得查詢[4,6]成為可能,因?yàn)槲夷莻€(gè)1加入來了,而不是一直用pos=2那個(gè)位置的1,再者,查詢[4,7]的話,一樣的意思,因?yàn)橹虚g的1進(jìn)來了。所以我們因?yàn)楸M量往右靠,畢竟我們都把query按R排序了。

還有這個(gè)只能離線,一直預(yù)處理ans[i]表示第i個(gè)詢問的ans。更新到[4,7]后,查詢[1,2]已經(jīng)不可能了,因?yàn)楹苊黠@,pos=2這個(gè)位置已經(jīng)被刪除了。

#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL;#include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> const int maxn = 1e6+20; int book[maxn]; int c[maxn];//樹狀數(shù)組,多case的記得要清空 int n; //我只需記錄這個(gè)位置是不是新元素,不用離散 int lowbit (int x)//得到x二進(jìn)制末尾0的個(gè)數(shù)的2次方 2^num {return x&(-x); } void add (int pos,int val)//在第pos位加上val這個(gè)值 {while (pos<=n) //n是元素的個(gè)數(shù) {c[pos] += val; pos += lowbit(pos);}return ; } int get_sum (int pos) //求解:1--pos的總和 {int ans = 0;while (pos){ans += c[pos]; pos -= lowbit(pos);}return ans; } int a[maxn]; struct node {int L,R,id;bool operator < (const struct node &rhs) const{if (R != rhs.R) return R < rhs.R;else return L < rhs.L;} }query[maxn]; int ans[maxn]; void work () {scanf("%d",&n);for (int i=1;i<=n;++i) scanf("%d",&a[i]);//樹狀數(shù)組含義:1--pos間的不同元素種類數(shù)int q; scanf("%d",&q);for (int i=1;i<=q;++i){scanf("%d%d",&query[i].L,&query[i].R);query[i].id = i; //記錄ans }sort(query+1,query+1+q);int cur = 1;//book[val]的含義,val這個(gè)元素出現(xiàn)的最右邊的位置for (int i=1;i<=q;++i){for (int j=cur;j<=query[i].R;++j){if (book[a[j]]) //這個(gè)元素在之前位置出現(xiàn)過,我們盡量往右,所以先刪除那個(gè)位置的種類數(shù),更新現(xiàn)在這個(gè)位置的種類數(shù)。因?yàn)檫@樣的話,使得查詢[4,5]是可能的add(book[a[j]],-1); //del 這個(gè)位置book[a[j]]=j; //更新這個(gè)位置的最右值add(j,1); //這個(gè)位置出現(xiàn)了新元素 }cur = query[i].R+1;ans[query[i].id] = get_sum(query[i].R) - get_sum(query[i].L-1);}for (int i=1;i<=q;++i)printf ("%d\n",ans[i]); }int main() { #ifdef localfreopen("data.txt","r",stdin); #endifwork();return 0; } View Code

?

HDU 3333?Turing Tree

一樣的,只不過是求元素的和。。把a(bǔ)dd那里的val改成a[i]即可,幻想它出現(xiàn)了val次,一統(tǒng)計(jì),就是了。

#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL;#include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> const int maxn = 30000 + 20; LL c[maxn];//樹狀數(shù)組,多case的記得要清空 int n; LL a[maxn]; struct node {int L,R,id;bool operator < (const struct node &rhs) const{return R < rhs.R;} }query[2*100000]; LL ans[2*100000]; map<LL,int>book; int lowbit (int x)//得到x二進(jìn)制末尾0的個(gè)數(shù)的2次方 2^num {return x&(-x); } void add (int pos,LL val)//在第pos位加上val這個(gè)值 {while (pos<=n) //n是元素的個(gè)數(shù) {c[pos] += val; pos += lowbit(pos);}return ; } LL get_sum (int pos) //求解:1--pos的總和 {LL ans = 0;while (pos){ans += c[pos]; pos -= lowbit(pos);}return ans; } void init () {memset(c,0,sizeof c);book.clear();return ; } void work () {init();scanf("%d",&n);for (int i=1;i<=n;++i) scanf("%I64d",&a[i]);int q;scanf ("%d",&q);for (int i=1;i<=q;++i){scanf("%d%d",&query[i].L,&query[i].R);query[i].id = i;}sort(query+1,query+1+q);int cur=1;for (int i=1;i<=q;++i){for (int j=cur;j<=query[i].R;++j){int t = book[a[j]];if (t){add(t,-a[j]);}book[a[j]]=j;add(j,a[j]);}cur = query[i].R+1;ans[query[i].id] = get_sum(query[i].R) - get_sum(query[i].L-1);}for (int i=1;i<=q;++i){printf ("%I64d\n",ans[i]);} }int main() { #ifdef localfreopen("data.txt","r",stdin); #endifint t;scanf ("%d",&t);while (t--) work();return 0; } View Code

?

轉(zhuǎn)載于:https://www.cnblogs.com/liuweimingcprogram/p/5805076.html

總結(jié)

以上是生活随笔為你收集整理的SPOJ 3267: DQUERY 树状数组,离线算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。