舉個例子,有幾個數可以通過lowbit產生0100呢?0001--lowbit-->0010-->lowbit-->0011-->lowbit-->0100,有三個數可以通過lowbit產生0100,加上它本身,總共維護了2^2個數的和。比如5(0101)沒有數可以通過lowbit產生,所以維護它本身乙個。6(0110)可以有5(0101)lowbit產生,所以維護兩個。
大家有沒有發現要通過lowbit產生x1xx(x代表未知數),只能通過x0xx+lowbit產生,而後面的xx可以是01,10,11,2^k怎麼得出來該明白了吧!以下就是add(i,x)函式了
void add(int i,int x)
}
我們可以看到每個以ci維護的只是一段區間和,那我們求字首和只需找到對應的幾個ci即可。
比如我們要求前6(0110)個數的字首和為c6 + c4。c6維護的是a[5]+a[6]。現在只需x -= lowbit(x)。0110-0010=0100。而0100永遠也不可能lowbit到0110(上面說過了),所以0110和0100維護的區間是完全沒有關係的。0100維護的是a[1]+a[2]+a[3]+a[4]。正好找到字首和。
為什麼這樣可行呢?0110後面維護2^1個數,0100維護的是2^2個數。加起來正好是6 = 0010 + 0100。再比如11100 = 00100 + 01000 + 10000,而這些數都可以通過lowbit產生,通過維護的個數和,我們很容易能夠驗證這樣的方法可行的。一下是求和函式。
int sum(int i)
return s;
}
#include using namespace std;
typedef long long ll;
int const n = 500000 + 10;
int d[n],n,m;
int lowbit(int x)
ll sum(int i)
return sum;
}void add(int i,int x)
}int main()
while(m--)
}
#include using namespace std;
int const n = 500000 + 10;
int n,m,d[n],a[n];
int lowbit(int x)
void add(int i,int x)
}int sum(int i)
return s;
}int main()else
} return 0;
}
#include using namespace std;
int const n = 200000 + 10;
typedef long long ll;
ll c1[n],c2[n],a[n];
int n,m,k;
ll lowbit(ll x)
void add(ll c[n],ll i,ll x)
}ll getsum(ll c[n],ll i)
return s;
}int main()
}
左右括號的方法。在乙個區間內種樹,相當於加一對括號。用樹狀陣列維護從起始到這個位置的左右括號的數量。區間內有左括號那麼一定有這一種型別的樹,只有離開了對應的右括號這種樹才沒有了。所以為了統計區間[x,y]內的樹種類,只需把y左邊左括號的個數-(x-1)左邊右括號的個數即可。
#include using namespace std;
int const n = 50000 + 10;
int c1[n],c2[n];
int n,m;
int lowbit(int x)
void add(int c[n],int i)
}int getsum(int c[n],int i)
return s;
}int main()else
}}
#include #include #include #include #include using namespace std;
int const n = 1000 + 10;
int n,m,c[n][n];
int lowbit(int x)
void add(int x,int y)
int sum(int x,int y)
int main()else
} }return 0;
}
這是一道樹狀陣列求逆序數的經典題目。注意要離散化,最後要開long long。
#include #include #include #include #include using namespace std;
typedef long long ll;
int const n = 500000 + 10;
int a[n],n,d[n];
ll ans;
vectorv;
int lowbit(int x)
void add(int i,int x)
}int sum(int i)
return s;
}int main()
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
memset(d,0,sizeof(d));
ans = 0;
for(int i=1;i<=n;i++)
printf("%lld\n",ans);
} return 0;
}
又是一道求逆序數的題目。先排序,x公升序,x相同y公升序。注意要long long,資料範圍不準確。
#include #include #include #include #include using namespace std;
int const n = 1000 + 10;
typedef long long ll;
int n,m,k,d[n];
ll ans;
struct road
}road[n*n];
int lowbit(int x)
void add(int i,int x)
}int sum(int i)
return s;
}int main()
void add(int i,int x)
}int sum(int i)
return s;
}int main()
for(int i=0;i<=n-1;i++) printf("%d\n",num[i]);
return 0;
}
pta 習題集 5 15 陣列迴圈左移
本題要求實現乙個對陣列進行迴圈左移的簡單函式 乙個陣列a a中存有n n 0 0 個整數,在不允許使用另外陣列的前提下,將每個整數迴圈向左移m m 0 0 個位置,即將a a中的資料由 a0a1 an 1a 0 a 1 a n 1 變換為 am an 1a0a1 am 1a m a n 1 a 0 ...
Python習題集(四)
如果乙個 3 位數等於其各位數字的立方和,則稱這個數為水仙花數。例如 153 1 3 5 3 3 3,因此 153 就是乙個水仙花數 那麼問題來了,求1000以內的水仙花數 3位數 int轉字串序列,獲取到每一位數 呼叫math.pow函式求立方和 三個數字立方和相加 lists for i in ...
Python習題集(十二)
請寫乙個函式find odd,引數是1個列表,請返回該列表 現奇數次的元素 比如 find odd 1,1,2,2,5,2,4,4,1,2,5 1 find odd 20,1,1,2,2,3,3,5,5,4,20,4,5 5 find odd 10 10 迴圈列表 呼叫列表內建統計函式計算當前元素出...