hdu1394线段树点修改,区间求和
鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1394
題意:給一個0-n-1的排列,這個排列中的逆序數為數對 (ai, aj)?滿足 i < j and ai > aj的個數。依次把第一個數放到排列的末尾會得到另外n-1個排列,求這n個排列中的最小的逆序數。
思路:關鍵是要把第一個排列的逆序數求出來,后面的排列可以遞推出來。假如第一個逆序數為s0,當把a0從首位移到末位時,新得到的s1應該是在s0的基礎上加上比a0大的數的個數,減去比a0小的數的個數。由于這一串數是一個0-n-1的排列,所以比a0大的數的個數為 (n-1)-(a0+1)+1=n-a0-1,比a0小的數的個數為 (a0-1)-0+1=a0,所以s1=n-a0-a0-1.第一次做個題的時候一直想不明白要怎么建樹,由于是滿足 i < j and ai > aj的條件,所以其實就是對于每個數aj,求比它大的數的個數。建樹的時候把每個節點都初始化為0,每當插入一個數,就在這個數對應的葉子節點上加1,同時更新包含這個點的線段所對應的非葉子節點(加1),一層層更新上去,區間求和。這樣如果存在某個數,在相應查找的時候就會找到。由于是要找比aj大的數,所以查找范圍就是aj-(n-1).如果還是想不明白的話,對著代碼手動模擬一遍就清楚了。
這里有個線段樹的講解,雖然不是這道題,但是覺得對理解線段樹挺有幫助的。http://hi.baidu.com/semluhiigubbqvq/item/be736a33a8864789f4e4ad18
#include <cstdio> #include <algorithm> using namespace std; #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 const int maxn = 5005; int sum[maxn<<2]; int a[maxn]; void PushUP(int rt)//更新每個節點的值,區間求和 {sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void build(int l,int r,int rt) {sum[rt]=0;if(l==r) return;int m=(l+r)>>1;build(lson);build(rson); } int query(int L,int R,int l,int r,int rt) {if(L<=l && r<=R)return sum[rt];int m=(l+r)>>1;int s=0;if(L<=m) s+=query(L,R,lson);if(R>m) s+=query(L,R,rson);return s; } void update(int p,int l,int r,int rt) {if(l==r){sum[rt]++;return;}int m=(l+r)>>1;if(p<=m) update(p,lson);else update(p,rson);PushUP(rt);//每次更新了葉子節點后,內部節點也要更新 } int main() {int n;while(~scanf("%d",&n)){build(0,n-1,1);int sum=0;for(int i=0;i<n;i++){scanf("%d",&a[i]);sum+=query(a[i],n-1,0,n-1,1);update(a[i],0,n-1,1);}int minm=sum;for(int i=0;i<n;i++){sum+=n-a[i]-a[i]-1;minm=min(minm,sum);}printf("%d\n",minm);}return 0; } View Code?
?
?
轉載于:https://www.cnblogs.com/54zyq/p/3268976.html
總結
以上是生活随笔為你收集整理的hdu1394线段树点修改,区间求和的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle10g 64位 在Windo
- 下一篇: 打包静默安装参数(nsis,msi,In