Introduction: http://blog.csdn.net/metalseed/article/details/8045038
Comprehension (drawing more vivid): http://blog.csdn.net/regina8023/article/details/41910615
Chairman Tree three frequently used points:
1. Enquiry Interval K-Large (online)
2. query interval k large and update node operation (offline, offline mainly to the line segment tree value discretization, if the value range is small do not need to be discretized, and do not need to be offline, and update operations need a nested tree array)
3. Query interval number of different numbers (tree array can be implemented, but only offline, the Chairman tree implementation can be online)
There are many line tree can be achieved, add some conditions, can be used to solve the Chairman tree.
Read the following question:
poj2104
Interval query k large elements, non-recursive writing, non-recursive bad backtracking operations, recursion better write some
#include <iostream> #include <stdio.h> #include <algorithm> using namespace std;
const int maxn=100005;
int n,m;
int v[maxn],b[maxn],t[maxn],tsize,tot=0; struct Charitree {int l,r,tsize;}
A[MAXN*30];
int build (int l,int r) {int root=tot++;
a[root].tsize=0;
if (l==r) return root;
int m= (L+R) >>1;
A[root].l=build (L,M);
A[root].r=build (M+1,R);
return root;
} int Update (int root,int x) {int now=tot++;
int Tmp=now;
a[now].tsize=a[root].tsize+1;
int l=1,r=tsize;
while (l<r) {int m= (L+R) >>1;
if (x<=m) {a[now].l=tot++;
A[NOW].R=A[ROOT].R;
NOW=A[NOW].L;
R=m;
ROOT=A[ROOT].L;
} else {a[now].l=a[root].l;
a[now].r=tot++;
NOW=A[NOW].R;
l=m+1;
ROOT=A[ROOT].R;
} a[now].tsize=a[root].tsize+1;
} return TMP; } int Ask (int Lx,int rx,int k) {int l=1,r=tsize;
while (l<r) {int m= (L+R) >>1;
if (a[a[rx].l].tsize-a[a[lx].l].tsize>=k) {r=m;
LX=A[LX].L;
RX=A[RX].L;
} else {l=m+1;
K-=a[a[rx].l].tsize-a[a[lx].l].tsize;
LX=A[LX].R;
RX=A[RX].R;
}} return L;
} void Hash1 () {sort (b+1,b+1+n);
Tsize=unique (b+1,b+1+n)-b-1;//redo Function} int find_index (int x) {return lower_bound (b+1,b+1+tsize,x)-B;} int main () {
int i,j,l,r,k;
cin>>n>>m;
for (i=1;i<=n;i++) scanf ("%d", &v[i]), b[i]=v[i];
Hash1 ();
T[0]=build (1,tsize);
for (i=1;i<=n;i++) t[i]=update (T[i-1],find_index (v[i));
while (m--) {cin>>l>>r>>k;
printf ("%d\n", B[ask (t[l-1],t[r],k)]);
} return 0;
}
Unique function: In STL, the unique function is a deduplication function, the unique function is to remove the adjacent repeating elements (only one), in fact, it does not really delete the duplicate elements, is to move the duplicate elements to the back, and then still saved to the original array, and then Returns the address of the last element after the deduplication, because unique removes the adjacent repeating elements, so it is usually used before the order is ordered.
HDU-4417
Interval query is less than or equal to the number of K, and the above question basically similar, modified the function of the query
#include <iostream> #include <stdio.h> #include <algorithm> using namespace std;
const int maxn=100005;
int n,m;
int v[maxn],b[maxn],t[maxn],tsize,tot=0; struct Charitree {int l,r,tsize;}
A[MAXN*30];
int build (int l,int r) {int root=tot++;
a[root].tsize=0;
if (l==r) return root;
int m= (L+R) >>1;
A[root].l=build (L,M);
A[root].r=build (M+1,R);
return root;
} int Update (int root,int x) {int now=tot++;
int Tmp=now;
a[now].tsize=a[root].tsize+1;
int l=1,r=tsize;
while (l<r) {int m= (L+R) >>1;
if (x<=m) {a[now].l=tot++;
A[NOW].R=A[ROOT].R;
NOW=A[NOW].L;
R=m;
ROOT=A[ROOT].L;
} else {a[now].l=a[root].l;
a[now].r=tot++;
NOW=A[NOW].R;
l=m+1;
ROOT=A[ROOT].R;
} a[now].tsize=a[root].tsize+1;
} return TMP; } int Ask (int Lx,int rx,int Le,int ri,int k) {if (b[ri]<=k) {return a[rx].tsize-a[lx].tsize;
} if (Le==ri) return 0;
int sum=0;
int m= (Le + ri) >> 1;
if (b[m+1]<=k) sum+=ask (a[lx].r,a[rx].r,m+1,ri,k);
Sum+=ask (A[LX].L,A[RX].L,LE,M,K);
return sum;
} void Hash1 () {sort (b+1,b+1+n);
Tsize=unique (b+1,b+1+n)-b-1;
} int Find_index (int x) {return lower_bound (b+1,b+1+tsize,x)-B;} int main () {int T;
int i,j,l,r,k;
cin>>t;
for (int tt = 1; TT <= T; tt++) {cin>>n>>m;
for (i=1;i<=n;i++) scanf ("%d", &v[i]), b[i]=v[i];
Hash1 ();
T[0]=build (1,tsize);
for (i=1;i<=n;i++) t[i]=update (T[i-1],find_index (v[i));
printf ("Case%d:\n", TT);
while (m--) {cin>>l>>r>>k;
l++,r++;
printf ("%d\n", Ask (T[l-1],t[r],1,tsize,k));
}} return 0; }
Spoj count on a tree
Test instructions: To a tree, each node has a weight, query two nodes on the path between the weights K small node
Chairman of the tree, and the title is only a linear contribution and the difference between the tree, each node by its parent node is modified, two nodes of the path of LCA to find a request. Query only, so it can be online
#include <iostream> #include <stdio.h> #include <algorithm> #include <vector> #include <
String.h> using namespace std;
const int maxn=100005;
int n,m;
int v[maxn],b[maxn],t[maxn],tsize,tot=0; struct Charitree {int l,r,tsize;}
A[MAXN*30];
vector<int>w[maxn];
int book[maxn],fa[maxn],dep[maxn],up[maxn][20];
int build (int l,int r) {int root=tot++;
a[root].tsize=0;
if (l==r) return root;
int m= (L+R) >>1;
A[root].l=build (L,M);
A[root].r=build (M+1,R);
return root;
} int Update (int root,int x) {int now=tot++;
int Tmp=now;
a[now].tsize=a[root].tsize+1;
int l=1,r=tsize;
while (l<r) {int m= (L+R) >>1;
if (x<=m) {a[now].l=tot++;
A[NOW].R=A[ROOT].R;
NOW=A[NOW].L;
R=m;
ROOT=A[ROOT].L;
} else {a[now].l=a[root].l;
a[now].r=tot++;
NOW=A[NOW].R; l=m+1;
ROOT=A[ROOT].R;
} a[now].tsize=a[root].tsize+1;
} return TMP;
} void Hash1 () {sort (b+1,b+1+n);
Tsize=unique (b+1,b+1+n)-b-1;
} int Find_index (int x) {return lower_bound (b+1,b+1+tsize,x)-B;} int init () {memset (up,0,sizeof (UP));
for (int i=1;i<=n;i++) up[i][0]=fa[i];
for (int. j=1;j<=16;j++) {for (int i=1;i<=n;i++) {up[i][j]=up[up[i][j-1]][j-1];
}}} int LCA (int lx,int rx) {if (Dep[lx]<dep[rx]) swap (LX,RX);
int A=RX,B=LX;
int C=dep[b]-dep[a];
for (int i=0;i<=16;i++) {if (c& (1<<i)) b=up[b][i];
} if (a==b) return A;
for (int i=16;i>=0;i--) {if (Up[a][i]!=up[b][i]) {a=up[a][i];
B=up[b][i];
}} return Fa[a];
} int Ask (int lx,int rx,int k) {int l=1,r=tsize;
int Mx=lca (LX,RX);
int F=FA[MX];
LX=T[LX]; RX=T[RX];
MX=T[MX];
F=T[F];
while (l<r) {int m= (L+R) >>1; cout<<b[m]<< "" <<a[a[rx].l].tsize<< "<<a[a[f].l].tsize<<" "<<A[A[LX"
.l].tsize<< "" <<a[a[mx].l].tsize<<endl; cout<<b[m]<< "" <<a[a[rx].r].tsize<< "<<a[a[f].r].tsize<<" "<<A[A[LX"
.r].tsize<< "" <<a[a[mx].r].tsize<<endl;
if (a[a[rx].l].tsize-a[a[f].l].tsize+a[a[lx].l].tsize-a[a[mx].l].tsize>=k) {r=m;
LX=A[LX].L;
F=A[F].L;
MX=A[MX].L;
RX=A[RX].L;
} else {l=m+1;
K-=a[a[rx].l].tsize-a[a[f].l].tsize+a[a[lx].l].tsize-a[a[mx].l].tsize;
LX=A[LX].R;
F=A[F].R;
MX=A[MX].R;
RX=A[RX].R;
}} return L; } void Dfs (int x) {for (int i=0;i<w[x].size (); i++) {if (book[w[x][I]]) continue;
Book[w[x][i]]=1;
dep[w[x][i]]=dep[x]+1;
Fa[w[x][i]]=x;
T[w[x][i]]=update (T[x],find_index (V[w[x][i]));
DFS (W[x][i]);
} return;
} int main () {int i,j,l,r,k;
cin>>n>>m;
for (i=1;i<=n;i++) scanf ("%d", &v[i]), b[i]=v[i];
for (i=1;i<n;i++) {scanf ("%d%d", &l,&r);
W[l].push_back (R);
W[r].push_back (l);
} hash1 ();
T[0]=build (1,tsize);
int root=1;
W[0].push_back (root);
book[0]=1;dep[0]=0;
DFS (0);
Init ();
while (m--) {cin>>l>>r>>k;
printf ("%d\n", B[ask (l,r,k)]);
} return 0;
}
ZOJ 2112 Dynamic Rankings
Ask for the interval k large value, but there are modification operations, need to set a tree array, because all points are discretized, so only offline operation
I try to write a, at the beginning of the direct tree array operation, in the corresponding point of achievement, so that the complexity of the space will be written in a tall, Zoj is also an infinite section error ... No matter how big the array is ...
According to Kuangbin template modified a bit, first in accordance with the original way, in the update not modify the original tree, but to build a new tree to save the modified value, so as if the space saving point .... However, it was a mistake to rewrite the code for a long time, until the array size just opened at 2500010. Change to 3000010 will prompt memory overrun, and then larger is a paragraph error ..... Puzzle Segment Error ...
#include <bits/stdc++.h> using namespace std;
const int maxn=60010;
const int m=2000010;
int SZ,N,LAGEN,M,TOT=0,V[MAXN],B[MAXN],S[MAXN],T[MAXN],USE[MAXN]; struct node {int l,r,sz;}
A[M];
struct question {char C;
int i,j,k;
};
int build (int l,int r) {int root=tot++;
a[root].sz=0;
if (l==r) return root;
int m= (L+R) >>1;
A[root].l=build (L,M);
A[root].r=build (M+1,R);
return root;
} int update (int root,int x,int k) {int now=tot++;
int Temp=now;
int l=0,r=sz-1,m;
A[now].sz=a[root].sz+k;
while (L<r) {m= (l+r) >>1;
if (x<=m) {a[now].l=tot++;
A[NOW].R=A[ROOT].R;
NOW=A[NOW].L;
ROOT=A[ROOT].L;
R=m;
} else {a[now].r=tot++;
A[NOW].L=A[ROOT].L;
NOW=A[NOW].R;
ROOT=A[ROOT].R;
l=m+1;
} a[now].sz=a[root].sz+k; } return TEmp
} int Add (int index,int x,int k) {while (index<=n) {s[index]=update (s[index],x,k);
index+=index&-index;
}} int Ask (int lx,int rx,int k) {int i,j;
int LX_ROOT=T[LX];
int RX_ROOT=T[RX];
for (I=lx;i;i-=i&-i) use[i]=s[i];
for (I=rx;i;i-=i&-i) use[i]=s[i];
int l=0,r=sz-1,m;
while (L<r) {m= (l+r) >>1;
int sum=0;
for (i=lx;i;i-=i&-i) Sum-=a[a[use[i]].l].sz;
for (i=rx;i;i-=i&-i) Sum+=a[a[use[i]].l].sz;
SUM+=A[A[RX_ROOT].L].SZ-A[A[LX_ROOT].L].SZ;
if (sum>=k) {r=m;
for (i=lx;i;i-=i&-i) USE[I]=A[USE[I]].L;
for (i=rx;i;i-=i&-i) USE[I]=A[USE[I]].L;
LX_ROOT=A[LX_ROOT].L;
RX_ROOT=A[RX_ROOT].L;
} else {l=m+1;
K-=sum; for (i=lx;i;i-=i&-i) use[i]=A[USE[I]].R;
for (i=rx;i;i-=i&-i) USE[I]=A[USE[I]].R;
LX_ROOT=A[LX_ROOT].R;
RX_ROOT=A[RX_ROOT].R;
}} return L;
} void Hash1 () {sort (B,b+lagen);
Sz=unique (B,b+lagen)-B;
} int Find_index (int x) {return lower_bound (b,b+sz,x)-B;} vector<question>w;
int main () {int t,i;
cin>>t;
while (t--) {tot=lagen=0;
cin>>n>>m;
for (i=1;i<=n;i++) scanf ("%d", &v[i]), b[lagen++]=v[i];
Question temp;
while (m--) {GetChar ();
Temp.c=getchar ();
if (temp.c== ' Q ') {scanf ("%d%d%d", &TEMP.I,&TEMP.J,&TEMP.K);
} else {scanf ("%d%d", &TEMP.I,&TEMP.J);
B[LAGEN++]=TEMP.J;
} w.push_back (temp);
} hash1 ();
T[0]=build (1,SZ); for (i=1;i<=n;i++) {t[i]=update (T[i-1],find_index (V[i]), 1);
S[I]=T[0]; } for (I=0;i<w.size (); i++) {if (w[i].c== ' Q ') {printf ("%d\n", b[
Ask (W[I].I-1,W[I].J,W[I].K)]);
} else {Add (W[i].i,find_index (v[w[i].i]),-1);
Add (W[i].i,find_index (W[I].J), 1);
V[W[I].I]=W[I].J;
}} w.clear ();
}
}
Spoj D-query
The number of different values in the query interval
The tree array can be done offline, first to save all the queries, and then according to the right end of the value of the sorting, the tree array stored value of 0 or 1, indicating that the subscript has no value, open a tag array, to ensure that the process of the original array each element appears only once
#include <bits/stdc++.h> #define EPS 1e-9 #define PI 3.141592653589793 #define BS 1000000007 #define Bsize #defin
e MEM (a) memset (A,0,sizeof (a)) typedef long Long LL;
using namespace Std;
const int maxn=30005,maxm=200005;
struct question {int l,r,index;
BOOL operator< (const question a) const {if (R==A.R) return l<a.l;
Return r<a.r;
}}QUERY[MAXM];
int n,f[maxn],a[maxn],ans[maxm],book[1000005];
int add (int x,int k) {while (x<=n) {f[x]+=k;
x+=x&-x;
}} int sum (int x) {int ans=0;
while (x) {ans+=f[x];
x-=x&-x;
} return ans;
} int main () {cin>>n;
int i,q;
for (i=1;i<=n;i++) scanf ("%d", &a[i]);
cin>>q;
for (i=0;i<q;i++) {scanf ("%d%d", &QUERY[I].L,&QUERY[I].R);
Query[i].index=i;
} sort (query,query+q);
int now=0;
for (i=1;i<=n&&now<q;i++) {if (Book[a[i]]) Add (book[a[i]],-1);
Add (i,1);
Book[a[i]]=i; while (QUERY[NOW].R<=I&&NOW<Q) {Ans[query[now].index]=sum (QUERY[NOW].R)-sum (QUERY[NOW].L-1);
now++;
}} for (i=0;i<q;i++) printf ("%d\n", Ans[i]);
return 0;
}
The Chairman tree can be implemented online, each node saved by the segment tree stored information for each point of value, is also 1 or 0, using a marker array to record the position before this number (subscript), my current node of the segment tree, and the previous node has a lot of public use of the part, so update the value of the new location, It is now the subscript, in the tag array to record the value of the previous position to assign 0, so that the current node's segment tree records the current position and the left anywhere between the number of different numbers,
#include <bits/stdc++.h> #define EPS 1e-9 #define PI 3.141592653589793 #define BS 1000000007 #define Bsize #defin
e MEM (a) memset (A,0,sizeof (a)) typedef long Long LL;
using namespace Std;
const int maxn=30005,maxm=200005; struct node {int l,r,sz;}
A[100*MAXN];
int BOOK[1000005],TOT=0,T[MAXN],N,V[MAXN];
int build (int l,int r) {int root=tot++;
a[root].sz=0;
int m= (L+R) >>1;
if (l!=r) {a[root].l=build (l,m);
A[root].r=build (M+1,R);
} return root;
} int update (int root,int x,int k) {int l=1,r=n;
int now=tot++;
int M,temp=now;
A[now].sz=a[root].sz+k;
while (L<r) {m= (l+r) >>1;
if (x<=m) {A[NOW].R=A[ROOT].R;
a[now].l=tot++;
NOW=A[NOW].L;
ROOT=A[ROOT].L;
R=m;
} else {a[now].l=a[root].l;
a[now].r=tot++;
NOW=A[NOW].R;
ROOT=A[ROOT].R;
l=m+1;
} a[now].sz=a[root].sz+k;
} return temp;
} int Ask (int root,int x) {int l=1,r=n,m;
int ans=a[root].sz;
while (L<r) {m= (l+r) >>1; if (x<=m) {root=a[root].l;
R=m;
} else {ans-=a[a[root].l].sz;
ROOT=A[ROOT].R;
l=m+1;
}} return ans;
} int main () {cin>>n;
int i,q;
T[0]=build (1,n);
for (i=1;i<=n;i++) {scanf ("%d", &v[i]);
if (Book[v[i]]) {t[i]=update (t[i-1],book[v[i]],-1);
T[i]=update (t[i],i,1);
} else T[i]=update (t[i-1],i,1);
Book[v[i]]=i;
} cin>>q;
int l,r;
for (i=0;i<q;i++) {scanf ("%d%d", &l,&r);
printf ("%d\n", Ask (t[r],l));
} return 0; }
There is a similar example, query interval number of different numbers, but added some operations to force the online query, cannot use the tree-like array
hdu-5919
#include <bits/stdc++.h> #define EPS 1e-9 #define PI 3.141592653589793 #define BS 1000000007 #define Bsize #defin
e MEM (a) memset (A,0,sizeof (a)) typedef long Long LL;
using namespace Std;
const int maxn=200005; struct node {int l,r,sz;}
A[50*MAXN];
int BOOK[MAXN],TOT=0,T[MAXN],N,V[MAXN],ANS[MAXN];
int build (int l,int r) {int root=tot++;
a[root].sz=0;
int m= (L+R) >>1;
if (l!=r) {a[root].l=build (l,m);
A[root].r=build (M+1,R);
} return root;
} int update (int root,int x,int k) {int l=1,r=n;
int now=tot++;
int M,temp=now;
A[now].sz=a[root].sz+k;
while (L<r) {m= (l+r) >>1;
if (x<=m) {A[NOW].R=A[ROOT].R;
a[now].l=tot++;
NOW=A[NOW].L;
ROOT=A[ROOT].L;
R=m;
} else {a[now].l=a[root].l;
a[now].r=tot++;
NOW=A[NOW].R;
ROOT=A[ROOT].R;
l=m+1;
} a[now].sz=a[root].sz+k;
} return temp;
} int Ask (int root,int x) {int l=1,r=n,m;
int ans=0;
while (L<r) {m= (l+r) >>1; if (x<m) {root=A[ROOT].L;
R=m;
} else {ans+=a[a[root].l].sz;
ROOT=A[ROOT].R;
l=m+1;
}} return ans;
} int solve (int root,int x) {int temp=ask (ROOT,X);
int k= (temp+1)/2;
int l=1,r=n,m;
while (L<r) {m= (l+r) >>1;
if (a[a[root].l].sz>=k) {root=a[root].l;
R=m;
} else {k-=a[a[root].l].sz;
ROOT=A[ROOT].R;
l=m+1;
}} return L;
} int main () {int t,i,q;
cin>>t;
for (int tcase=1;tcase<=t;tcase++) {tot=0;
memset (book,0,sizeof (book));
cin>>n>>q;
T[n+1]=build (1,n);
for (i=1;i<=n;i++) scanf ("%d", &v[i]);
for (i=n;i>=1;i--) {if (Book[v[i]) {t[i]=update (t[i+1],book[v[i]],-1);
T[i]=update (t[i],i,1);
} else T[i]=update (t[i+1],i,1);
Book[v[i]]=i;
} int L,r,le,ri;
ans[0]=0;
for (i=1;i<=q;i++) {scanf ("%d%d", &le,&ri);
L=min ((Ans[i-1]+le)%n+1, (Ans[i-1]+ri)%n+1);
R=max ((Ans[i-1]+le)%n+1, (Ans[i-1]+ri)%n+1);
Ans[i]=solve (T[L],R);
} printf ("Case #%d:", tcase);
for (i=1;i<=q;i++) {printf ("%d", ans[i]);
} cout<<endl;
} return 0; }