http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=604&pid=1002
Dylans loves sequence
Dylans is given N
numbers a[1]....a[N]
And there are Q
questions.
Each question is like this (L,R)
his goal is to find the “inversions” from number L
to number R
.
more formally,his needs to find the numbers of pair(x,y
), that L≤x,y≤R
and x<y
and a[x]>a[y]
In the first line there is two numbers N
and Q
.
Then in the second line there are N
numbers:a[1]..a[N]
In the next Q
lines,there are two numbers L,R
in each line.
N≤1000,Q≤100000,L≤R,1≤a[i]≤2 31 −1
For each query,print the numbers of "inversions”
3 2 3 2 1 1 2 1 3
1 3
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <string> #include <vector> #include <cmath> using namespace std; int dp[1005][1005],dp2[1005][1005]; int main() { int n,Q; while(scanf("%d%d",&n,&Q)==2) { int a[1005]; for(int i=0;i<n;++i) scanf("%d",&a[i]); for(int i=0;i<n;++i) { dp[i][i]=0; for(int j=i+1;j<n;++j) { dp[i][j]=dp[i][j-1]; if(a[j]<a[i]) dp[i][j]++; } } for(int i=0;i<n;++i) { dp2[i][0]=dp[0][i]; for(int j=1;j<=i;++j) dp2[i][j]=dp2[i][j-1]+dp[j][i]; } while(Q--) { int l,r; scanf("%d%d",&l,&r); l--;r--; if(l==0) printf("%d\n",dp2[r][r]); else printf("%d\n",dp2[r][r]-dp2[r][l-1]); } } return 0; }
//樹狀數組寫法
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; int i,j,m,n,p,k,a[1005],q,b[1005],tree[1005],l,r,ans[1005][1005]; int lowbit(int x) { return x&-x; } int ask(int x) { int sum=0; for (;x;x-=lowbit(x)) sum+=tree[x]; return sum; } int ins(int x) { for (;x<=b[0];x+=lowbit(x)) tree[x]++; } int main() { scanf("%d%d",&n,&q); for (i=1;i<=n;++i) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+n+1); b[0]=unique(b+1,b+n+1)-(b+1); for (i=1;i<=n;++i) a[i]=lower_bound(b+1,b+b[0]+1,a[i])-b; for (i=1;i<=n;++i) { memset(tree,0,sizeof(tree)); for (j=i;j<=n;++j) { ans[i][j]=ans[i][j-1]+ask(b[0])-ask(a[j]); ins(a[j]); } } for (;q--;) { scanf("%d%d",&l,&r); printf("%d\n",ans[l][r]); } }
線段樹:
《1》http://poj.org/problem?id=3264(簡單題,練模板)


#include<cstdio> #include<algorithm> #include<iostream> using namespace std; const int MAXN = 200005; const int INF = 1000000000; int nMax, nMin; struct Node{ int L, R; int nMin, nMax; }segTree[MAXN*3]; int a[MAXN]; void Build(int i, int L, int R) { segTree[i].L = L; segTree[i].R = R; if(L==R) { segTree[i].nMin = segTree[i].nMax = a[L]; return; } int mid = (L+R)>>1; Build(i<<1, L, mid); Build(i<<1|1, mid+1, R); segTree[i].nMin=min(segTree[i<<1].nMin, segTree[i<<1|1].nMin); segTree[i].nMax=max(segTree[i<<1].nMax, segTree[i<<1|1].nMax); } void Query(int i, int L, int R) { if(segTree[i].nMax<=nMax&&segTree[i].nMin>=nMin) return; if(segTree[i].L==L&&segTree[i].R==R) { nMax = max(segTree[i].nMax, nMax); nMin = min(segTree[i].nMin, nMin); return; } int mid = (segTree[i].L+segTree[i].R)>>1; if(R<=mid) Query(i<<1, L, R); else if(L>mid) Query(i<<1|1, L, R); else { Query(i<<1, L, mid); Query(i<<1|1, mid+1, R); } } int main() { int n, q, L, R, i; while(scanf("%d%d", &n, &q)!=EOF) { for(i=1; i<=n; i++) scanf("%d", &a[i]); Build(1, 1, n); for(i=1; i<=q; i++) { scanf("%d%d", &L, &R); nMax = -INF; nMin = INF; Query(1, L, R); printf("%d\n", nMax-nMin); } } return 0; }
《2》http://acm.hdu.edu.cn/showproblem.php?pid=1166(簡單題, 用模板)


#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 50000+5; int num[MAXN]; struct Node{ int l, r; int nSum; }segTree[MAXN*3]; void Build(int i, int l, int r) { segTree[i].l = l; segTree[i].r = r; if(l==r) { segTree[i].nSum=num[l]; return; } int mid=(l+r)>>1; Build(i<<1, l, mid); Build(i<<1|1, mid+1, r); segTree[i].nSum=segTree[i<<1].nSum+segTree[i<<1|1].nSum; } void Add(int i, int t, int b) { segTree[i].nSum+=b; if(segTree[i].l==t&&segTree[i].r==t) return; int mid=(segTree[i].l+segTree[i].r)>>1; if(t<=mid) Add(i<<1, t, b); else Add(i<<1|1, t, b); } int Query(int i, int l, int r) { if(segTree[i].l==l&&segTree[i].r==r) return segTree[i].nSum; int mid=(segTree[i].l+segTree[i].r)>>1; if(r<=mid) return Query(i<<1, l, r); else if(l>mid) return Query(i<<1|1, l, r); else return Query(i<<1, l, mid)+Query(i<<1|1, mid+1, r); } int main() { int T; int kase; int n, i; char str[10]; int a, b; scanf("%d", &T); for(kase=1; kase<=T; kase++) { scanf("%d", &n); for(i=1; i<=n; i++) scanf("%d", &num[i]); Build(1, 1, n); printf("Case %d:\n", kase); while(scanf("%s", &str)) { if(str[0]=='E') break; //if(strcmp(str,"End")==0) break; scanf("%d%d", &a, &b); if(str[0]=='A') Add(1, a, b); //if(strcmp(str, "Add")==0) Add(1, a, b); else if(str[0]=='S') Add(1, a, -b); //else if(strcmp(str, "Sub")==0) Add(1, a, -b); else printf("%d\n", Query(1, a, b)); } } return 0; }
《3》http://poj.org/problem?id=3468(進階題)


#include<cstdio> #include<algorithm> #include<iostream> using namespace std; const int MAXN = 100000; int num[MAXN]; struct Node{ int l, r; long long nSum; long long Inc; }segTree[MAXN*3]; void Build(int i, int l, int r)//建立線段樹 { segTree[i].l=l; segTree[i].r=r; segTree[i].Inc=0; if(l==r) { segTree[i].nSum=num[l]; return; } int mid=(l+r)>>1; Build(i<<1, l, mid); Build(i<<1|1, mid+1, r); segTree[i].nSum=segTree[i<<1].nSum+segTree[i<<1|1].nSum; } void Add(int i, int a, int b, long long c)//在結點i的區間(a,b)上增加c { if(segTree[i].l==a&&segTree[i].r==b)//這個過程和建樹過程相似。 { segTree[i].Inc+=c; return; } segTree[i].nSum+=c*(b-a+1); int mid=(segTree[i].l+segTree[i].r)>>1; if(b<=mid) Add(i<<1, a, b, c); else if(a>mid) Add(i<<1|1, a, b, c); else { Add(i<<1, a, mid, c); Add(i<<1|1, mid+1, b, c); } } long long Query(int i, int a, int b)//查詢a-b的總和 { if(segTree[i].l==a&&segTree[i].r==b) { return segTree[i].nSum+(b-a+1)*segTree[i].Inc; } segTree[i].nSum+=(segTree[i].r-segTree[i].l+1)*segTree[i].Inc; int mid=(segTree[i].l+segTree[i].r)>>1; Add(i<<1, segTree[i].l, mid, segTree[i].Inc); Add(i<<1|1, mid+1, segTree[i].r, segTree[i].Inc); segTree[i].Inc = 0; if(b<=mid) return Query(i<<1, a, b); else if(a>mid) return Query(i<<1|1, a, b); else return Query(i<<1, a, mid)+Query(i<<1|1, mid+1, b); } int main() { int n, q; int i; int a, b, c; char ch; while(scanf("%d%d", &n, &q)!=EOF) { for(i=1; i<=n; i++) scanf("%d", &num[i]); Build(1, 1, n); for(i=1; i<=q; i++) { cin>>ch; if(ch=='C') { scanf("%d%d%d", &a, &b, &c); Add(1, a, b, c); } else { scanf("%d%d", &a, &b); printf("%I64d\n", Query(1, a, b)); } } } return 0; }
《4》http://acm.hdu.edu.cn/showproblem.php?pid=1754(簡單題)


#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 200000+10; int num[MAXN]; struct Node { int l, r; int nMax; }segTree[MAXN*4]; void Build(int i, int l, int r) { segTree[i].l=l; segTree[i].r=r; if(l==r) { segTree[i].nMax=num[l]; return; } int mid=(segTree[i].l+segTree[i].r)>>1; Build(i<<1, l, mid); Build(i<<1|1, mid+1, r); segTree[i].nMax=max(segTree[i<<1].nMax, segTree[i<<1|1].nMax); } void Update(int i, int l, int r, int x) { if(segTree[i].l==l&&segTree[i].r==r) { segTree[i].nMax=x; return; } int mid=(segTree[i].l+segTree[i].r)>>1; if(r<=mid) Update(i<<1, l, r, x); else if(l>mid) Update(i<<1|1, l, r, x); else { Update(i<<1, l, mid, x); Update(i<<1|1, mid+1, r, x); } segTree[i].nMax=max(segTree[i<<1].nMax, segTree[i<<1|1].nMax); } int Query(int i, int l, int r) { if(segTree[i].l==l&&segTree[i].r==r) { return segTree[i].nMax; } int mid=(segTree[i].l+segTree[i].r)>>1; if(r<=mid) return Query(i<<1, l, r); else if(l>mid) return Query(i<<1|1, l, r); else return max(Query(i<<1, l, mid), Query(i<<1|1, mid+1, r)); } int main() { int n, m; while(scanf("%d%d", &n, &m)!=EOF) { int i, j, k, a, b; char s[2]; for(i=1; i<=n; i++) scanf("%d", &num[i]); Build(1, 1, n); for(i=0; i<m; i++) { scanf("%s%d%d", s, &a, &b); if(s[0]=='U') Update(1, a, a, b); else printf("%d\n", Query(1, a, b)); } } return 0; }
《5》http://acm.hdu.edu.cn/showproblem.php?pid=2795
線段樹, 適用的范圍還真廣!!。 這個題看到別人能用線段樹切, 也是非常的機智。


/*以墻的高度和廣告數量的較小值建線段樹 , 樹中v表示該段中最大空余量,idid表示最大 空余量所在行 (從上開始記)。每次貼廣告 先比較空余量, 從上到下,空余足夠就貼, 再根據查找到的空余行進行點更新。。。 */ #include<cstdio> #include<algorithm> #include<iostream> using namespace std; const int MAXN = 200000+10; int h, v, n; struct Node { int l, r; int id; int v; }segTree[MAXN*4]; void Build(int i, int l, int r) { segTree[i].l = l; segTree[i].r = r; segTree[i].id = l; segTree[i].v = v; if(l==r) return; int mid=(l+r)>>1; Build(i<<1, l, mid); Build(i<<1|1, mid+1, r); } int Query(int i, int val) { if(segTree[i].v<val) return -1; if(segTree[i].l==segTree[i].r) return segTree[i].id; if(segTree[i<<1].v>=val) return Query(i<<1, val); else return Query(i<<1|1, val); } void Update(int i, int l, int r, int val) { if(segTree[i].l==l&&segTree[i].r==r) { segTree[i].v-=val; return; } int mid=(segTree[i].l+segTree[i].r)>>1; if(r<=mid) Update(i<<1, l, r, val); else if(l>mid) Update(i<<1|1, l, r, val); if(segTree[i<<1].v>segTree[i<<1|1].v) { segTree[i].v = segTree[i<<1].v; segTree[i].id = segTree[i<<1].id; } else { segTree[i].v = segTree[i<<1|1].v; segTree[i].id = segTree[i<<1|1].id; } } int main() { while(scanf("%d%d%d", &h, &v, &n)!=EOF) { int j, k; if(h>n) h = n; Build(1, 1, h); for(int q=0; q<n; q++) { scanf("%d", &k); int t; t = Query(1, k); printf("%d\n",t); if(t!=-1) Update(1, t, t, k); } } return 0; }
《6》http://acm.hdu.edu.cn/showproblem.php?pid=1394(求逆序數)
線段樹法:


#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int MAXN=5000+10; int a[MAXN]; struct Node { int l,r; int sum; }segTree[MAXN*3]; void Build(int i,int l,int r) { segTree[i].l=l; segTree[i].r=r; if(l==r) { segTree[i].sum=0; return; } int mid=(l+r)>>1; Build(i<<1,l,mid); Build((i<<1)|1,mid+1,r); segTree[i].sum=0; } void add(int i,int t,int val) { segTree[i].sum+=val; if(segTree[i].l==segTree[i].r) { return; } int mid=(segTree[i].l+segTree[i].r)>>1; if(t<=mid) add(i<<1,t,val); else add((i<<1)|1,t,val); } int sum(int i,int l,int r) { if(segTree[i].l==l&&segTree[i].r==r) return segTree[i].sum; int mid=(segTree[i].l+segTree[i].r)>>1; if(r<=mid) return sum(i<<1,l,r); else if(l>mid) return sum((i<<1)|1,l,r); else return sum(i<<1,l,mid)+sum((i<<1)|1,mid+1,r); } int main() { int n; while(scanf("%d",&n)!=EOF) { Build(1,0,n-1); for(int i=0;i<n;i++) scanf("%d",&a[i]); int ans=0; for(int i=0;i<n;i++) { ans+=sum(1,a[i],n-1); add(1,a[i],1); } int Min=ans; for(int i=0;i<n;i++) { ans-=a[i];//減少的逆序數 ans+=n-a[i]-1;//增加的逆序數 if(ans<Min)Min=ans; } printf("%d\n",Min); } return 0; }
線段樹求逆序數, 其實就是將輸入的數組元素依次插入線段樹, 線段樹的段值sum表示該段中以插入的數字個數。每次插入,計算已插入的比插入數大的數的個數,總和就是逆序數。
樹狀數組法:(先占個坑, 嘿嘿!)
《7》http://poj.org/problem?id=2528(線段樹+離散)
這道題看似并不復雜,然而此坑甚深。 本來想暴力一下的, 結果,,,,, 其實大多數的能用線段樹解決的問題,都有比較簡單的暴力思路, 然而大都卡時間。這就體現出線段樹的高效性啦! 。 這也是為何算法令人如癡如醉的一個原因-------------高效性。
暴力該打:


#include<iostream> #include<cstdio> #include<cstring> #include<set> using namespace std; const int MAXN = 10000000+10; int a[MAXN]; int main() { int T, n; int l, r; scanf("%d", &T); while(T--) { set<int> ss; memset(a, 0, sizeof(a)); scanf("%d", &n); for(int i=1; i<=n; i++) { scanf("%d%d", &l, &r); for(int j=l; j<=r; j++) a[j] = i; } for(int i=0; i<MAXN; i++) ss.insert(a[i]); printf("%d\n",ss.size()-1); } return 0; }
反對暴力, 提倡和諧!
文章列表