线段树（堆式）[单点更新， 区间查询]

http://acm.hdu.edu.cn/showproblem.php?pid=1166

first blood of seg-tree  单点增减 区间求和

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=60000+123;
int T[maxn*2];
int M;

int bit(int x)/// get highest 1 in bit-number
{
if(x==0)return 0;
int n=1;
if((x>>16)==0){n+=16; x<<=16;}
if((x>>24)==0){n+=8; x<<=8;}
if((x>>28)==0){n+=4; x<<=4;}
if((x>>30)==0){n+=2; x<<=2;}
return 32-n-(x>>31);
}

void Updata(int x, int v)
{
for (T[x+=M]+=v, x>>=1; x; x>>=1) //
T[x]=T[x<<1]+T[(x<<1)+1]; /// updata father by their children
}

int request(int s, int t)
{
int res=0;
for (s+=M-1, t+=M+1; s^t^1; s>>=1, t>>=1)/// change [,] to (,); s^t==1 refer to the interval is empty
{
if(~s&1) res+=T[s^1];
if( t&1) res+=T[t^1];
}
return res;
}

int main ()
{
int cas;
scanf("%d", &cas);
for (int I=1; I<=cas; ++I)
{
printf("Case %d:\n", I);
int n;
///initialization
scanf("%d", &n);
M=1<<(bit(n));
//        printf("---%d  %d\n", M, bit(n));
memset (T, 0, sizeof(T));
for (int i=0; i<n; ++i)
scanf("%d",  &T[i+M]);
for (int i=(n+M-1)/2; i>0; --i)/// (n+m-1)/2 is largest non-leaf node
T[i]=T[2*i]+T[2*i+1];

char op[20];
int a, b;
while (~scanf("%s", op))
{
if (op[0]=='E')
break;
scanf("%d %d", &a, &b);
if (op[0]=='Q')
printf("%d\n", request(a-1, b-1));
if (op[0]=='A')
Updata(a-1, b);
if (op[0]=='S')
Updata(a-1, -b);
}
}
return 0;
}

hdu1394 Minimum Inversion Number

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=5000+123;
int T[maxn*3];
int a[maxn];
int M;
int bit(int x)/// get highest 1 in bit-number
{
if(x==0)return 0;
int n=31;
if((x>>16)==0){n-=16; x<<=16;}
if((x>>24)==0){n-=8; x<<=8;}
if((x>>28)==0){n-=4; x<<=4;}
if((x>>30)==0){n-=2; x<<=2;}
return n-(x>>31);
}

int Query(int s, int t)
{
int res=0;
for (s+=M-1, t+=M+1; s^t^1; s>>=1, t>>=1)
{
if(~s&1) res+=T[s^1];
if( t&1) res+=T[t^1];
}
return res;
}

void Updata(int x)
{
for (T[x+=M]=1, x>>=1; x; x>>=1)
T[x]=T[x<<1]+T[(x<<1)+1];
}

void init(int x)
{
memset (T, 0, sizeof(T));
M=1<<bit(x);
}

int main ()
{
int n;
while (~scanf("%d", &n))
{
init(n);
int inv=0;
for (int i=0; i<n; ++i)
{
scanf("%d", a+i);
inv+=Query(a[i]+1, n-1);
Updata(a[i]);
}
int ans=inv;
for (int i=0; i<n-1; ++i)
{
inv+=n-a[i]-a[i]-1;
ans=min(inv, ans);
}
printf("%d\n", ans);
}
return 0;
}

void Updata (int x, int v)
{
for (T[x+=M]-=v, x>>=1; x; x>>=1)
T[x]=max(T[x<<1], T[x<<1|1]);
}

int Query (int s, int t, int x)
{
int res=-1, r;
s+=M-1;t+=M+1;
for (r=1; (r<<1)<t;)
{
T[r<<1]>=x?(r<<=1):(r=(r<<1|1));
}
if(r>s && r<t)res=r;
else res=t;
return res;
}

http://www.acdream.net/problem.php?id=1123

第一次找aj>ai ，且j>i的对数， 然后再次维护一个新树， 找3元组的个数

dp[i][1] 表示 有多少对 aj > ai，j < i,dp[i][2]表示有多少对ak > aj > ai , k < j < i

dp[i][1] += dp[j][0] ( aj > ai 且 j < i)

dp[i][2] += dp[j][1] ( aj > ai 且 j < i)

long long Request(int s, int t)
{
long long res=0;
for (s+=M-1, t+=M+1; s^t^1; s>>=1, t>>=1)
{
if(~s&1) res+=T[s^1];
if( t&1) res+=T[t^1];
}
return res;
}

void Updata(int x, int v)
{
for (T[x+=M]+=v, x>>=1; x; x>>=1)
T[x]=T[x<<1]+T[x<<1|1];
}

void init()
{
M=1<<bit(n);
memset (T, 0, sizeof(T));
}

int main ()
{
while (~scanf("%d", &n))
{
init();
memset (inv, 0, sizeof(inv));
for (int i=0; i<n; ++i)/// 得到一次逆序，
{
scanf("%d", a+i);
inv[i]=Request(a[i]+1, n)+inv[i];
Updata(a[i], 1);
}
memset (T, 0, sizeof(T));
long long ans=0;
for (int i=0; i<n; ++i)
{
ans=Request(a[i]+1, n)+ans;
Updata(a[i], inv[i]);
}
printf("%lld\n", ans);
}
return 0;
}

• 本文已收录于以下专栏：

举报原因： 您举报文章：线段树（堆式）[单点更新， 区间查询] 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)