1. 程式人生 > >一些趣題的回憶

一些趣題的回憶

clas 常常 root getch temp 分治 printf cto 題目

  這種題目,常常道聽途說,或是考試用題。常常難覓出處,卻又非常經典。故選其精華,小列如下。


T1:fleet 給定一個序列,詢問[L,R]間有多少種不同的權值。

e.g.:序列1,1,2,3,2的[1,5]有3種不同權值,[1,3]有2種不同權值。

ANSWER:可以考慮使用主席樹求解。查詢[L,R]時返回root[R]的[L,R]值之和。root[i]與root[i-1]的不同在於:prev[aa[i]]這個位置(即上一次出現aa[i]的位置)-1,在i這個位置+1。先預處理完畢,再應付查詢。


T2:給定一個序列,詢問[L,R]間有多少種權值k恰出現k次。

e.g.:序列1,1,2,3,2的[1,1]有1種權值,[1,2]有0種權值,[2,5]有2種權值。

ANSWER:可以考慮使用主席樹求解。但是,我們也可以考慮使用離線。因為答案本質上統計的是一種情形,而我們可以考慮該情形對答案的貢獻。如果把詢問[L,R]轉化為二維矩陣中某點[L,R]的權值,那麽每一種情形的貢獻也可以看做是矩形的修改。因為這樣很令人不爽,可以進一步地轉換,使用差分的思想,將矩形拆成4個角,問題於是轉化為單點修改與矩陣前綴和的查詢。這個東西很像BZOJ的一道題:MONICA。那是一道CDQ分治套樹狀數組的典型題目,因為有時間的先後。但是,這道題目完全可以先修改再查詢,於是可以sort以後直接使用樹狀數組求解。

 1 #define PN "count"
 2 #include <cstdio>
 3
#include <cstring> 4 #include <algorithm> 5 template<class T>inline void readint(T &res) { 6 static char ch;T flag=1; 7 while((ch=getchar())<0||ch>9)if(ch==-)flag=-1; 8 res=ch-48; 9 while((ch=getchar())>=0&&ch<=9)res=res*10
+ch-48; 10 res*=flag; 11 } 12 const int N = 1000000 + 100; 13 const int Q = 1000000 + 100; 14 struct DATUM { 15 int x, y, delta; 16 bool operator<(const DATUM &rhs) const { 17 if(x!=rhs.x) return x<rhs.x; 18 if(y!=rhs.y) return y<rhs.y; 19 if(delta!=rhs.delta) return delta<rhs.delta; 20 } 21 } data[N*4+Q]; 22 int tot, ans[Q]; 23 inline void addD(int x,int y,int delta) {data[++tot]=(DATUM){x,y,delta};} 24 25 int n, a[N]; 26 void add(int pos,int val) {for(int x=pos;x<=n;x+=x&-x)a[x]+=val;} 27 int query(int pos) {int val=0;for(int x=pos;x;x-=x&-x)val+=a[x];return val;} 28 29 #include <vector> 30 std::vector<int> same[N]; 31 int main() { 32 int q;readint(n);readint(q); 33 for( int i = 1; i <= n; i++ ) same[i].push_back(0); 34 for( int i = 1, x, siz; i <= n; i++ ) { 35 readint(x);same[x].push_back(i); 36 siz=same[x].size(); 37 if(siz>x) { 38 addD(same[x][siz-x-1]+1,i,+1); 39 addD(same[x][siz-x]+1,i,-1); 40 if(siz>x+1) addD(same[x][siz-x-2]+1,i,-1); 41 if(siz>x+1) addD(same[x][siz-x-1]+1,i,+1); 42 } 43 } 44 for( int i = 1, l, r; i <= q; i++ ) readint(l),readint(r),addD(l,r,i+1); 45 std::sort(data+1,data+tot+1); 46 for( int i = 1; i <= tot; i++ ) { 47 if(data[i].delta<=1) add(data[i].y,data[i].delta); 48 else if(data[i].y>=1&&data[i].y<=n) ans[data[i].delta-1]=query(data[i].y); 49 } 50 for( int i = 1; i <= q; i++ ) printf("%d\n",ans[i]); 51 return 0; 52 }

未完待續……

一些趣題的回憶