今天主要内容:1.RMQ算法
2.树状数组
3.线段树
(一)RMQ算法
Description
For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbee with some of the cows. To keep things simple, he will take a contiguous range of cows from the milking lineup to play the game. However, for all the cows to have fun they should not differ too much in height.
Farmer John has made a list of Q (1 ≤ Q ≤ 200,000) potential groups of cows and their heights (1 ≤ height ≤ 1,000,000). For each group, he wants your help to determine the difference in height between the shortest and the tallest cow in the group.
Input
Output
Sample Input
6 3 1 7 3 4 2 5 1 5 4 6 2 2
Sample Output
6 3 0
#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<vector> #include<cstring> using namespace std; typedef long long LL; const int maxN = 200010; int f1[maxN][32]; int f2[maxN][32]; int n,q; int logN[maxN]; int Max(int a, int b){ return a>b?a:b; } int Min(int a, int b){ return a>b?b:a; } void init(){ memset(logN, 0, sizeof(logN)); for(int i=0 ;i<maxN; ++i){ for(int j= 0 ;j<32; ++j){ f1[i][j]=0; f2[i][j]=0; } } } void init_RMQ(){ logN[1]= 0; for(int i =2 ;i<=maxN;++i){ logN[i] =((i&(i-1))==0)?logN[i-1]+1:logN[i-1]; } for(int j=1; j<=logN[n]; ++j){ for(int i=1; i+(1<<j)-1<=n;++i){ f1[i][j] = Max(f1[i][j-1],f1[i+(1<<(j-1))][j-1]); } } for(int j=1; j<=logN[n];++j){ for(int i=1; i+(1<<j)-1<=n;++i){ f2[i][j] = Min(f2[i][j-1],f2[i+(1<<(j-1))][j-1]); } } } int ANS(int x, int y){ int k = logN[y-x+1]; return Max(f1[x][k],f1[y-(1<<k)+1][k]) - Min(f2[x][k],f2[y-(1<<k)+1][k]); } int main(){ scanf("%d %d",&n,&q); init(); for(int i=1 ;i<=n;++i){ scanf("%d",&f1[i][0]); f2[i][0] =f1[i][0]; } init_RMQ(); /* for(int i=0 ;i<=n;++i){ for(int j=0 ;j<logN[n];++j) cout<<f[i][j]<<" "; cout<<endl; }*/ for(int j=1; j<=q; ++j){ int a, b; scanf("%d%d", &a, &b); printf("%d\n",ANS(a,b)); } }
(二)树状数组
超牛逼的算法好吗!!!不知道创造这种方法的人的脑子是怎么长的!!!
如果不记得了可以看看:http://blog.csdn.net/int64ago/article/details/7429868
Description
Input
Output
Sample Input
Sample Output
//判断输入语句可以用strcmp来判断 #include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<vector> #include<cstring> using namespace std; typedef long long LL; const int maxN = 50010; int N; int tree[maxN]; int lowbit(int x){ return x&-x; } void add(int k, int num){ while(k<=N){ tree[k]+=num; k+=lowbit(k); } } LL sum(int k){ LL ans = 0; while(k){ ans+=tree[k]; k-=lowbit(k); } return ans; } int main() { int T; scanf("%d",&T); for(int i=1; i<=T;++i){ memset(tree,0,sizeof(tree)); printf("Case %d:\n",i); scanf("%d", &N); for(int i = 1 ; i<=N; ++i){ int num; scanf("%d",&num); add(i,num); } char s[10]; memset(s,0,sizeof(s)); while(scanf("%s",s)!=EOF){ if(!strcmp(s,"End")) break; if(!strcmp(s,"Add")){ int a, b; scanf("%d%d", &a, &b); add(a,b); } if(!strcmp(s,"Sub")){ int a, b; scanf("%d%d", &a, &b); add(a,-b); } if(!strcmp(s,"Query")){ int a, b; scanf("%d%d", &a, &b); printf("%lld\n", sum(b)-sum(a-1)); } } } return 0; }
Description
Input
Output
Sample Input
Sample Output
Hint
Huge input,the C function scanf() will work better than cin
//这题又让我知道了一点,就算是读入单个字符也不要用scanf("%c")会超时,另外,scanf("%d,&tree[root])如果少了&的话,或者无限循环,都会出现段错误 #include<iostream> #include<cstdio> #include<algorithm> using namespace std; typedef long long LL; const int maxN = 800005; const int INF = 0; int tree[maxN]; void build_tree(int left, int right, int root){ if(left==right){ scanf("%d",&tree[root]); return ; } int mid = (left+right)>>1; build_tree(left,mid,root<<1); build_tree(mid+1,right,root<<1|1); tree[root] = max(tree[root<<1],tree[root<<1|1]); } void update(int id, int grade, int left, int right, int root){ if(left==right){ tree[root] = grade; return ; } int mid = (left+right)>>1; if(id<=mid) update(id,grade,left,mid,root<<1); else update(id,grade,mid+1,right,root<<1|1); tree[root] = max(tree[root<<1], tree[root<<1|1]); } int Query(int tleft, int tright, int left, int right, int root){ if(tleft<=left && tright>=right){ return tree[root]; } else{ int ans = INF; int mid = (left+right)>>1; if(tleft<=mid) ans= max(ans, Query(tleft,tright,left,mid,root<<1)); if(tright>mid) ans= max(ans, Query(tleft,tright,mid+1,right,root<<1|1)); return ans; } } int main(){ int n, m; while(scanf("%d %d", &n, &m)!=EOF){ build_tree(1,n,1); while(m--){ int a, b; char s[3]; scanf("%s%d%d", s, &a, &b); if(s[0]=='Q'){ printf("%d\n", Query(a,b,1,n,1)); } if(s[0]=='U') update(a,b,1,n,1); } } return 0; }
Description
给出了一个序列,你需要处理如下两种询问。
"C a b c"表示给[a, b]区间中的值全部增加c (-10000 ≤ c ≤ 10000)。
"Q a b" 询问[a, b]区间中所有值的和。
Input
第一行包含两个整数N, Q。1 ≤ N,Q ≤ 100000.
第二行包含n个整数,表示初始的序列A (-1000000000 ≤ Ai ≤ 1000000000)。
接下来Q行询问,格式如题目描述。
Output
对于每一个Q开头的询问,你需要输出相应的答案,每个答案一行。
Sample Input
10 5 1 2 3 4 5 6 7 8 9 10 Q 4 4 Q 1 10 Q 2 4 C 3 6 3 Q 2 4
Sample Output
4 55 9 15
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; typedef long long LL; const int maxN = 500005; LL sum[maxN], add[maxN]; struct node{ int l, r; int mid(){ return (l+r)>>1; } }tree[maxN]; void PushUp(int rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void PushDown(int rt, int m){ if(add[rt]){ add[rt<<1] += add[rt]; add[rt<<1|1] += add[rt]; sum[rt<<1] += add[rt]*(m - (m>>1)); sum[rt<<1|1] += add[rt]*(m>>1); add[rt] = 0; } } void build (int l, int r, int rt){ tree[rt].l = l ; tree[rt].r = r ; add[rt] = 0; if(l == r){ scanf("%lld", &sum[rt]); return ; } int m = tree[rt].mid(); build(l,m, rt<<1); build(m+1, r, rt<<1|1); PushUp(rt); } void update(int c, int l, int r, int rt){ if(tree[rt].l ==l && tree[rt].r ==r){ add[rt] += c; sum[rt] += c*(r-l+1) ; //cichu return ; } if(tree[rt].l == tree[rt].r) return ; PushDown(rt, tree[rt].r - tree[rt].l +1); int m = tree[rt].mid(); if( r<= m) update(c, l, r, rt<<1); else if(l > m) update(c, l, r, rt<<1|1); else{ update(c, l, m, rt<<1); update(c, m+1, r, rt<<1|1); } PushUp(rt); } LL query(int l, int r, int rt){ if(l == tree[rt].l && r==tree[rt].r){ return sum[rt]; } PushDown(rt, tree[rt].r - tree[rt].l +1); int m = tree[rt].mid(); LL res = 0 ; if(r<=m) res+= query(l, r, rt<<1); else if(l>m) res+= query(l, r, rt<<1|1); else { res += query(l, m, rt<<1); res += query(m+1, r, rt<<1|1); } return res; } int main(){ int n, m; while(scanf("%d %d", &n, &m)!=EOF){ build(1,n,1); while(m--){ char ch[2]; scanf("%s", ch); int a, b, c; if(ch[0] == 'Q'){ scanf("%d %d", &a, &b); printf("%lld\n", query(a, b, 1)); } else { scanf("%d %d %d", &a, &b, &c); update(c, a, b, 1); } } } return 0; }