1.(HDOJ6278)http://acm.hdu.edu.cn/showproblem.php?pid=6278
2.(CF961E)http://codeforces.com/problemset/problem/961/E
3.(CF1000F)http://codeforces.com/problemset/problem/1000/F
4.(CF916D)https://www.luogu.org/problemnew/show/CF916D
5.(CQOI2015)https://www.luogu.org/problemnew/show/P3168
6.(POI2014)https://www.luogu.org/problemnew/show/P3567
7.(SCOI2016)https://www.luogu.org/problemnew/show/P3293
8.(SDOI2010)https://www.luogu.org/problemnew/show/P2468
9.(P4137)https://www.luogu.org/problemnew/show/P4137
1.(HDOJ6278)http://acm.hdu.edu.cn/showproblem.php?pid=6278
题意:给定一个长度为n的序列,和q个询问,求每个询问[l,r]中最大的h,满足该区间内至少有h个数的值大于h。
分析:主席树+二分答案。每次二分后求区间第mid小的数与mid比较

1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<vector>
5 using namespace std;
6 const int maxn=1e5+10;
7 const int maxm=5e6+10;
8 int n,q,m,tot;
9 int a[maxn],t[maxn];
10 int T[maxn],lson[maxm],rson[maxm],c[maxm];
11
12 void init_hash()
13 {
14 for ( int i=1;i<=n;i++ ) t[i]=a[i];
15 sort(t+1,t+1+n);
16 m=unique(t+1,t+1+n)-(t+1);
17 }
18
19 int build(int l,int r)
20 {
21 int root=tot++;
22 c[root]=0;
23 if ( l!=r )
24 {
25 int mid=(l+r)/2;
26 lson[root]=build(l,mid);
27 rson[root]=build(mid+1,r);
28 }
29 return root;
30 }
31
32 int hash_(int x)
33 {
34 return lower_bound(t+1,t+1+m,x)-t;
35 }
36
37 int update(int root,int pos,int val)
38 {
39 int rt=tot++,tmp=rt;
40 c[rt]=c[root]+val;
41 int l=1,r=m;
42 while ( l<r )
43 {
44 int mid=(l+r)/2;
45 if ( pos<=mid )
46 {
47 lson[rt]=tot++;rson[rt]=rson[root];
48 rt=lson[rt];root=lson[root];
49 r=mid;
50 }
51 else
52 {
53 rson[rt]=tot++;lson[rt]=lson[root];
54 rt=rson[rt];root=rson[root];
55 l=mid+1;
56 }
57 c[rt]=c[root]+val;
58 }
59 return tmp;
60 }
61
62 int query(int lrt,int rrt,int k)
63 {
64 if ( k==0 ) return 0;
65 int l=1,r=m;
66 while ( l<r )
67 {
68 int mid=(l+r)/2;
69 if ( c[lson[rrt]]-c[lson[lrt]]>=k )
70 {
71 r=mid;
72 lrt=lson[lrt];
73 rrt=lson[rrt];
74 }
75 else
76 {
77 l=mid+1;
78 k-=c[lson[rrt]]-c[lson[lrt]];
79 lrt=rson[lrt];
80 rrt=rson[rrt];
81 }
82 }
83 return l;
84 }
85
86 int main()
87 {
88 int Case;
89 while ( scanf("%d%d",&n,&q)!=EOF )
90 {
91 tot=0;
92 for ( int i=1;i<=n;i++ ) scanf("%d",&a[i]);
93 init_hash();
94 T[0]=build(1,m);
95 for ( int i=1;i<=n;i++ )
96 {
97 int pos=hash_(a[i]);
98 T[i]=update(T[i-1],pos,1);
99 }
100 while ( q-- )
101 {
102 int l,r,k,mid,L,R,num;
103 scanf("%d%d",&l,&r);
104 L=1,R=r-l+2;
105 while ( R-L>1 )
106 {
107 mid=(L+R)/2;
108 k=t[query(T[l-1],T[r],r-l+1-mid+1)];
109 if ( k>=mid ) L=mid;
110 else R=mid;
111 }
112 printf("%d\n",L);
113 }
114 }
115 return 0;
116 }
2.(CF961E)http://codeforces.com/problemset/problem/961/E
题意:有一个电视剧总共有n季,每季有a[i]季,现有第i季第j集与第j季第i集冲突(算一对),现求有多少对冲突
分析:主席树。首先对所有a[i]>n的数,都将其变成a[i]=n。同时对于所有a[i]>i的数来说会多算一对,将其减去。对于每个i来说,想知道有多少对冲突,只需要在T[a[i]]的版本中求出>=i的数的个数有多少。这样计算所有的方案会重复算一次,除掉2即可。

1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<vector>
5 using namespace std;
6 typedef long long ll;
7 const int maxn=2e5+10;
8 const int maxm=5e6+10;
9 int n,q,tot;
10 int a[maxn];
11 int T[maxn],lson[maxm],rson[maxm],c[maxm];
12
13 int build(int l,int r)
14 {
15 int root=tot++;
16 c[root]=0;
17 if ( l!=r )
18 {
19 int mid=(l+r)/2;
20 lson[root]=build(l,mid);
21 rson[root]=build(mid+1,r);
22 }
23 return root;
24 }
25
26 int update(int root,int pos,int val)
27 {
28 int rt=tot++,tmp=rt;
29 c[rt]=c[root]+val;
30 int l=1,r=n;
31 while ( l<r )
32 {
33 int mid=(l+r)/2;
34 if ( pos<=mid )
35 {
36 lson[rt]=tot++;rson[rt]=rson[root];
37 rt=lson[rt];root=lson[root];
38 r=mid;
39 }
40 else
41 {
42 rson[rt]=tot++;lson[rt]=lson[root];
43 rt=rson[rt];root=rson[root];
44 l=mid+1;
45 }
46 c[rt]=c[root]+val;
47 }
48 return tmp;
49 }
50
51 int query(int lrt,int rrt,int k)
52 {
53 int ret=0;
54 int l=1,r=n;
55 while ( l<r )
56 {
57 int mid=(l+r)/2;
58 if ( k<=mid )
59 {
60 ret+=c[rson[rrt]]-c[rson[lrt]];
61 r=mid;
62 lrt=lson[lrt];
63 rrt=lson[rrt];
64 }
65 else
66 {
67
68 l=mid+1;
69 lrt=rson[lrt];
70 rrt=rson[rrt];
71 }
72 }
73 ret+=c[rrt]-c[lrt];
74 return ret;
75 }
76
77 int main()
78 {
79 int Case,h;
80 ll ans;
81 while ( scanf("%d",&n)!=EOF )
82 {
83 ans=0;
84 tot=0;
85 for ( int i=1;i<=n;i++ )
86 {
87 scanf("%d",&a[i]);
88 if ( a[i]>=n ) a[i]=n;
89 if ( a[i]>=i ) ans--;
90 }
91 T[0]=build(1,n);
92 for ( int i=1;i<=n;i++ )
93 {
94 int pos=a[i];
95 T[i]=update(T[i-1],pos,1);
96 }
97 for ( int i=1;i<=n;i++ ) ans+=query(T[0],T[a[i]],i);
98 printf("%lld\n",ans/2);
99 }
100 return 0;
101 }
3.(CF1000F)http://codeforces.com/problemset/problem/1000/F
题意:给定一段序列a[],每次求一个区间[l,r]中只出现一次的数(任意输出一个即可)
分析:设置数组pre[i]表示值为i的数上一次出现的位置,初始化为0. 数组last[i]表示a[i]这个值上一次出现的位置。对于一个区间来说我们只需要求出该区间中最小的last[i],在与该区间左端点的位置进行比较即可。线段树用于保存结构体,结构体含val(区间最小值)和pos(区间最小值所对应的位置),线段树维护该区间最小的last[i].
离线线段树做法:按所有访问的区间右端点从小到大进行排序,可以保证在当前区间下后面的值不会对该区间产生影响。
主席树做法:对于访问区间[l,r]来说,每次访问第r个版本的线段树,在求区间[l,r]的最小值即可,原理同上

1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<map>
5 using namespace std;
6 #define lson l,m,rt*2
7 #define rson m+1,r,rt*2+1
8 #define root 1,n,1
9 typedef long long ll;
10 const int maxn=5e5+10;
11 const int maxm=5e5+10;
12 const int inf=1e9;
13 int ans[maxn],a[maxn],pre[maxn],last[maxn];
14 struct node{
15 int val,pos;
16 }arr[maxn*4];
17 struct Query{
18 int l;
19 int r;
20 int index;
21 }Q[maxm];
22
23 void pushup(int rt)
24 {
25 if ( arr[rt*2].val<=arr[rt*2+1].val ) arr[rt]=arr[rt*2];
26 else arr[rt]=arr[rt*2+1];
27 }
28
29 void build(int l,int r,int rt)
30 {
31 if ( l==r ) {
32 arr[rt].val=0;
33 arr[rt].pos=l;
34 return;
35 }
36 int m=(l+r)/2;
37 build(lson);
38 build(rson);
39 pushup(rt);
40 }
41
42 void update(int p,int val,int l,int r,int rt)
43 {
44 if ( l==r ) {
45 arr[rt].val=val;
46 return;
47 }
48 int m=(l+r)/2;
49 if ( p<=m ) update(p,val,lson);
50 else update(p,val,rson);
51 pushup(rt);
52 }
53
54 node query(int L,int R,int l,int r,int rt)
55 {
56 node Ans,Ans_;
57 if ( L<=l && r<=R ) return arr[rt];
58 int m=(l+r)/2;
59 int ret=inf;
60 int k,p;
61 if ( L<=m )
62 {
63 Ans=query(L,R,lson);
64 if ( Ans.val<ret )
65 {
66 ret=Ans.val;
67 k=Ans.pos;
68 }
69 }
70 if ( m<R )
71 {
72 Ans=query(L,R,rson);
73 if ( Ans.val<ret )
74 {
75 ret=Ans.val;
76 k=Ans.pos;
77 }
78 }
79 Ans_.val=ret;
80 Ans_.pos=k;
81 return Ans_;
82 }
83
84 bool cmp(Query a,Query b)
85 {
86 return a.r<b.r;
87 }
88
89 int main()
90 {
91 int T,i,j,k,n,m,x,y,z,cnt;
92 while ( scanf("%d",&n)!=EOF ) {
93 for ( i=1;i<=n;i++ ) scanf("%d",&a[i]);
94 memset(last,0,sizeof(last));
95 memset(pre,0,sizeof(pre));
96 for ( i=1;i<=n;i++ )
97 {
98 if ( pre[a[i]] ) last[i]=pre[a[i]];
99 pre[a[i]]=i;
100 }
101 build(root);
102 scanf("%d",&m);
103 for ( i=1;i<=m;i++ ) {
104 scanf("%d%d",&Q[i].l,&Q[i].r);
105 Q[i].index=i;
106 }
107 sort(Q+1,Q+1+m,cmp);
108 cnt=1;
109 for ( i=1;i<=m;i++ ) {
110 for ( ;cnt<=Q[i].r;cnt++ )
111 {
112 if ( last[cnt] ) update(last[cnt],inf,root);
113 update(cnt,last[cnt],root);
114 }
115 node Ans=query(Q[i].l,Q[i].r,root);
116 x=Ans.val;
117 if ( x>=Q[i].l ) ans[Q[i].index]=0;
118 else ans[Q[i].index]=a[Ans.pos];
119 }
120 for ( i=1;i<=m;i++ ) printf("%d\n",ans[i]);
121 }
122 return 0;
123 }

1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 using namespace std;
5 typedef long long ll;
6 const int maxn=5e5+10;
7 const int maxm=4e7+10;
8 const int inf=1e9;
9 struct node{
10 int val,pos;
11 }c[maxm];
12 int tot,n,q;
13 int a[maxn],t[maxn],pre[maxn],last[maxn],index[maxn];
14 int lson[maxm],rson[maxm];
15 int T[maxn];
16
17 void build(int &root,int l,int r)
18 {
19 root=++tot;
20 c[root].val=inf;
21 if ( l==r ) return;
22 int mid=(l+r)/2;
23 build(lson[root],l,mid);
24 build(rson[root],mid+1,r);
25 }
26
27 void update(int root,int &rt,int p,int val,int l,int r)
28 {
29 rt=++tot;
30 lson[rt]=lson[root],rson[rt]=rson[root];
31 if ( l==r )
32 {
33 c[rt].pos=l;
34 c[rt].val=val;
35 return;
36 }
37 int mid=(l+r)/2;
38 if ( p<=mid ) update(lson[rt],lson[rt],p,val,l,mid);
39 else update(rson[rt],rson[rt],p,val,mid+1,r);
40 if ( c[lson[rt]].val<c[rson[rt]].val ) c[rt]=c[lson[rt]];
41 else c[rt]=c[rson[rt]];
42 }
43
44 node query(int rt,int L,int R,int l,int r)
45 {
46 node Ans,Ans_;
47 if ( L<=l && r<=R ) return c[rt];
48 int m=(l+r)/2;
49 int ret=inf;
50 int k;
51 if ( L<=m )
52 {
53 Ans=query(lson[rt],L,R,l,m);
54 if ( Ans.val<ret )
55 {
56 ret=Ans.val;
57 k=Ans.pos;
58 }
59 }
60 if ( m<R )
61 {
62 Ans=query(rson[rt],L,R,m+1,r);
63 if ( Ans.val<ret )
64 {
65 ret=Ans.val;
66 k=Ans.pos;
67 }
68 }
69 Ans_.val=ret;
70 Ans_.pos=k;
71 return Ans_;
72 }
73
74 int main()
75 {
76 int Case;
77 while ( scanf("%d",&n)!=EOF )
78 {
79 tot=0;
80 for ( int i=1;i<=n;i++ ) scanf("%d",&a[i]);
81 memset(last,0,sizeof(last));
82 memset(pre,0,sizeof(pre));
83 for ( int i=1;i<=n;i++ )
84 {
85 if ( pre[a[i]] ) last[i]=pre[a[i]];
86 pre[a[i]]=i;
87 }
88 build(T[0],1,n);
89 for ( int i=1;i<=n;i++ )
90 {
91 if ( last[i] )
92 {
93 int tmp;
94 update(T[i-1],tmp,last[i],inf,1,n);
95 update(tmp,T[i],i,last[i],1,n);
96 }
97 else update(T[i-1],T[i],i,last[i],1,n);
98 }
99 scanf("%d",&q);
100 while ( q-- )
101 {
102 int l,r,k;
103 scanf("%d%d",&l,&r);
104 node A=query(T[r],l,r,1,n);
105 if ( A.val>=l ) printf("0\n");
106 else printf("%d\n",a[A.pos]);
107 }
108 }
109 return 0;
110 }
4.(CF916D)https://www.luogu.org/problemnew/show/CF916D
分析:建两棵主席树。对于每个字符(与任务对应)都有其特定的编号和优先级。一颗主席树(记作A),记录每个编号的字符对应的优先级。另外一棵主席树(记作B)记录每个优先级下有多少个字符。
wt代表主席树A的根节点编号,root代表主席树B的根节点编号
对于set操作:先判断是否已经存在,如果本身不存在,在A中对于其编号的位置添加值(值的大小为优先级).
若已经存在,先在主席树A中确定他原来的优先级p,更新成新的优先级k。在主席树B中p的位置-1,k的位置+1
对于操作remove:先在A中确定其优先级p,再更新为0。在B中p的位置-1
对于操作query:先在A中确定其优先级p,在B中求出优先级为【1,p-1】的个数。若为0,则表示不存在。
对于操作undo k:让root[i]=root[i-k+1],wt[i]=wt[i-k+1](返回历史版本)
注意:该题为强制在线,所以一开始不需要build建树,而是用到哪部分才在该部分建树
代码来自于https://www.luogu.org/problemnew/solution/CF916D

1 #include<cstdio>
2 #include<iostream>
3 #include<cstring>
4 #include<map>
5 using namespace std;
6 const int inf=1e9;
7 const int maxn=1e5+10;
8 const int maxm=1e7+10;
9 map<string,int>mp;
10 int root[maxn],wt[maxn],tot=0,top=0;
11 string s,op;
12 struct node
13 {
14 int lson,rson,w;
15 }A[maxm];
16
17 int getid(string s)
18 {
19 if ( mp.count(s) ) return mp[s];
20 return mp[s]=++top;
21 }
22
23 void update(int x,int y,int v)
24 {
25 A[x].lson=A[y].lson;
26 A[x].rson=A[y].rson;
27 A[x].w=A[y].w+v;
28 }
29
30 void change(int &rt,int root,int pos,int val,int l,int r)
31 {
32 rt=++tot;
33 update(rt,root,val);
34 if ( l==r ) return;
35 int mid=(r-l)/2+l;
36 if ( pos<=mid ) change(A[rt].lson,A[root].lson,pos,val,l,mid);
37 else change(A[rt].rson,A[root].rson,pos,val,mid+1,r);
38 }
39
40 int query(int rt,int L,int R,int l,int r)
41 {
42 if ( L<=l && r<=R ) return A[rt].w;
43 int mid=(r-l)/2+l;
44 int sum=0;
45 if ( L<=mid ) sum+=query(A[rt].lson,L,R,l,mid);
46 if ( R>mid ) sum+=query(A[rt].rson,L,R,mid+1,r);
47 return sum;
48 }
49
50 int main()
51 {
52 int q,k;
53 scanf("%d",&q);
54 for ( int i=1;i<=q;i++ )
55 {
56 cin>>op;
57 root[i]=root[i-1],wt[i]=wt[i-1];
58 if ( op[0]=='s' )
59 {
60 cin>>s>>k;
61 int id=getid(s);
62 int p=query(wt[i],id,id,1,inf);
63 if ( p ) change(root[i],root[i],p,-1,1,inf);
64 change(root[i],root[i],k,1,1,inf);
65 change(wt[i],wt[i],id,k-p,1,inf);
66 }
67 else if ( op[0]=='r' )
68 {
69 cin>>s;
70 int id=getid(s);
71 int p=query(wt[i],id,id,1,inf);
72 if ( p ) change(root[i],root[i],p,-1,1,inf);
73 change(wt[i],wt[i],id,-p,1,inf);
74 }
75 else if ( op[0]=='q' )
76 {
77 cin>>s;
78 int id=getid(s);
79 int p=query(wt[i],id,id,1,inf);
80 if ( !p ) printf("-1\n");
81 else if ( p==1 ) printf("0\n");
82 else printf("%d\n",query(root[i],1,p-1,1,inf));
83 fflush(stdout);
84 }
85 else if ( op[0]=='u' )
86 {
87 cin>>k;
88 root[i]=root[i-k-1];
89 wt[i]=wt[i-k-1];
90 }
91 }
92 return 0;
93 }
6.(POI2014)https://www.luogu.org/problemnew/show/P3567
题意:给一个数列,每次询问一个区间内有没有一个数出现次数超过一半
分析:主席树维护每个值(hash后)的数量,每次查询时保证最多只有一边大于总区间长的一半,最后当l==r时进行判断即可

1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 using namespace std;
5 typedef long long ll;
6 const int maxn=5e5+10;
7 const int maxm=1e7+10;
8 int tot,n,q,m;
9 int a[maxn],t[maxn];
10 int c[maxm],lson[maxm],rson[maxm];
11 int T[maxn];
12
13 void init_hash()
14 {
15 for ( int i=1;i<=n;i++ ) t[i]=a[i];
16 sort(t+1,t+1+n);
17 m=unique(t+1,t+1+n)-(t+1);
18 }
19
20 int hash_(int x)
21 {
22 return lower_bound(t+1,t+1+m,x)-t;
23 }
24
25
26 void build(int &root,int l,int r)
27 {
28 root=++tot;
29 if ( l==r ) return;
30 int mid=(l+r)/2;
31 build(lson[root],l,mid);
32 build(rson[root],mid+1,r);
33 }
34
35 void update(int root,int &rt,int p,int val,int l,int r)
36 {
37 rt=++tot;
38 lson[rt]=lson[root],rson[rt]=rson[root];
39 c[rt]=c[root]+val;
40 if ( l==r ) return;
41 int mid=(l+r)/2;
42 if ( p<=mid ) update(lson[rt],lson[rt],p,val,l,mid);
43 else update(rson[rt],rson[rt],p,val,mid+1,r);
44 }
45
46 int query(int lrt,int rrt,int cnt,int l,int r)
47 {
48 if ( l==r )
49 {
50 if ( c[rrt]-c[lrt]>cnt ) return l;
51 else return 0;
52 }
53 int mid=(l+r)/2;
54 int ans=0;
55 if ( c[lson[rrt]]-c[lson[lrt]]>cnt ) ans=query(lson[lrt],lson[rrt],cnt,l,mid);
56 else if ( c[rson[rrt]]-c[rson[lrt]]>cnt ) ans=query(rson[lrt],rson[rrt],cnt,mid+1,r);
57 return ans;
58 }
59
60 int main()
61 {
62 while ( scanf("%d%d",&n,&q)!=EOF )
63 {
64 tot=0;
65 for ( int i=1;i<=n;i++ ) scanf("%d",&a[i]);
66 init_hash();
67 build(T[0],1,m);
68 for ( int i=1;i<=n;i++ )
69 {
70 int pos=hash_(a[i]);
71 update(T[i-1],T[i],pos,1,1,m);
72 }
73 while ( q-- )
74 {
75 int l,r,k;
76 scanf("%d%d",&l,&r);
77 printf("%d\n",t[query(T[l-1],T[r],(r-l+1)/2,1,m)]);
78 }
79 }
80 return 0;
81 }
来源:https://www.cnblogs.com/HDUjackyan/p/9296000.html
