参考胡浩大神的线段树总结,并完成全部习题,后持续更新!
题意
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lson rt<<1
#define rson rt<<1|1
const int MAXN=5e4+10;
int tree[MAXN<<2];
void push_up(int rt){
tree[rt]=tree[lson]+tree[rson];
}
void build(int l,int r,int rt){
if(l==r){
scanf("%d",&tree[rt]);
return;
}
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
push_up(rt);
}
void update(int pos,int val,int l,int r,int rt){
if(l==r){
tree[rt]+=val;
return;
}
int mid=(l+r)>>1;
if(pos<=mid)update(pos,val,l,mid,lson);
else update(pos,val,mid+1,r,rson);
push_up(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return tree[rt];
}
int mid=(l+r)>>1;
int res=0;
if(mid>=L)res+=query(L,R,l,mid,lson);
if(mid+1<=R)res+=query(L,R,mid+1,r,rson);
return res;
}
int main(){
int T;
scanf("%d",&T);
rep(kase,1,T){
int n;
scanf("%d",&n);
printf("Case %d:\n",kase);
build(1,n,1);
char op[10];
while(true){
scanf("%s",op);
if(op[0]=='E')break;
if(op[0]=='Q'){
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",query(x,y,1,n,1));
}else if(op[0]=='S'){
int x,y;
scanf("%d%d",&x,&y);
update(x,-y,1,n,1);
}else{
int x,y;
scanf("%d%d",&x,&y);
update(x,y,1,n,1);
}
}
}
return 0;
}
题意
#include<bits/stdc++.h>
using namespace std;
#define lson rt<<1
#define rson rt<<1|1
const int MAXN=2e5+10;
int tree[MAXN<<2];
void push_up(int rt){
tree[rt]=max(tree[lson],tree[rson]);
}
void build(int l,int r,int rt){
if(l==r){
scanf("%d",&tree[rt]);
return;
}
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
push_up(rt);
}
void update(int pos,int val,int l,int r,int rt){
if(l==r){
tree[rt]=val;
return;
}
int mid=(l+r)>>1;
if(pos<=mid)update(pos,val,l,mid,lson);
if(pos>mid)update(pos,val,mid+1,r,rson);
push_up(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return tree[rt];
}
int mid=(l+r)>>1;
int res=-1;
if(mid>=L)res=max(res,query(L,R,l,mid,lson));
if(mid+1<=R)res=max(res,query(L,R,mid+1,r,rson));
return res;
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
build(1,n,1);
while(m--){
char op[5];
scanf("%s",op);
if(op[0]=='Q'){
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",query(x,y,1,n,1));
}else{
int x,y;
scanf("%d%d",&x,&y);
update(x,y,1,n,1);
}
}
}
return 0;
}
题意
- 一个序列的头元素可以循环放置到尾部,问整个过程中,最小的逆序数对。
思路
- 先求逆序数对,点更新区间和查询
- 然后遍历每次移动操作对逆序数对的影响就好了
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lson rt<<1
#define rson rt<<1|1
const int MAXN=5e3+10;
int a[MAXN];
int tree[MAXN<<2];
void push_up(int rt){
tree[rt]=tree[lson]+tree[rson];
}
void build(int l,int r,int rt){
if(l==r){
tree[rt]=0;
return;
}
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
push_up(rt);
}
void update(int pos,int l,int r,int rt){
if(l==r){
tree[rt]++;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid)update(pos,l,mid,lson);
if(pos>mid)update(pos,mid+1,r,rson);
push_up(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return tree[rt];
}
int mid=(l+r)>>1;
int res=0;
if(mid>=L)res+=query(L,R,l,mid,lson);
if(mid+1<=R)res+=query(L,R,mid+1,r,rson);
return res;
}
int main(){
int n;
while(~scanf("%d",&n)){
int sum=0;
rep(i,1,n){
scanf("%d",&a[i]);
a[i]++;
}
build(1,n,1);
rep(i,1,n){
sum+=query(a[i],n,1,n,1);
update(a[i],1,n,1);
}
int ans=sum;
rep(i,1,n){
sum-=a[i]-1;
sum+=n-a[i];
ans=min(ans,sum);
}
printf("%d\n",ans);
}
return 0;
}
题意
- 在固定长宽的墙上贴长为一的海报,模拟的规则就是能往上贴就尽量选上边的
- 问每张海报贴在第几行
思路
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lson rt<<1
#define rson rt<<1|1
const int MAXN=2e5+10;
int tree[MAXN<<2];
void push_up(int rt){
tree[rt]=max(tree[lson],tree[rson]);
}
void build(int v,int l,int r,int rt){
if(l==r){
tree[rt]=v;
return;
}
int mid=(l+r)>>1;
build(v,l,mid,lson);
build(v,mid+1,r,rson);
push_up(rt);
}
int query(int v,int l,int r,int rt){
if(l==r){
tree[rt]-=v;
return l;
}
int mid=(l+r)>>1;
int res;
if(tree[lson]>=v)res=query(v,l,mid,lson);
else res=query(v,mid+1,r,rson);
push_up(rt);
return res;
}
int main(){
int h,w,n;
while(~scanf("%d%d%d",&h,&w,&n)){
build(w,1,min(h,n),1);
rep(i,1,n){
int x;
scanf("%d",&x);
if(tree[1]<x){
puts("-1");
}else{
printf("%d\n",query(x,1,min(h,n),1));
}
}
}
return 0;
}
题意
- 有n个k维点,可以进行单点坐标修改,询问从l到r点中曼哈顿距离最大的点对的曼哈顿距离
思路
- 化简式子得到 max((x1+y1+z1+…)+(-x2-y2-z2-…))
- 其中左右两边要异号。
- 维护各状态的最大值就好了。
- 经典题型
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lson rt<<1
#define rson rt<<1|1
const int MAXN=8e5+100;
const int INF=1e9;
int tree[32][MAXN];
int n,k;
int K;
inline void push_up(int rt){
rep(i,0,K){
tree[i][rt]=max(tree[i][lson],tree[i][rson]);
}
}
int w[32];
inline void change(int rt){
rep(i,1,k){
scanf("%d",&w[i]);
}
rep(i,0,K){
int res=0;
rep(j,0,k-1){
if(i&(1<<j)){
res+=w[j+1];
}else{
res-=w[j+1];
}
}
tree[i][rt]=res;
}
}
void build(int l,int r,int rt){
if(l==r){
change(rt);
return;
}
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
push_up(rt);
}
void update(int pos,int l,int r,int rt){
if(l==r){
change(rt);
return;
}
int mid=(l+r)>>1;
if(pos<=mid)update(pos,l,mid,lson);
else update(pos,mid+1,r,rson);
push_up(rt);
}
void query_max(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
rep(i,0,K){
w[i]=max(w[i],tree[i][rt]);
}
return;
}
int mid=(l+r)>>1;
if(mid>=L)query_max(L,R,l,mid,lson);
if(mid+1<=R)query_max(L,R,mid+1,r,rson);
}
int main(){
scanf("%d%d",&n,&k);
K=(1<<k)-1;
build(1,n,1);
int q;
scanf("%d",&q);
while(q--){
int op;
scanf("%d",&op);
if(op==1){
int pos;
scanf("%d",&pos);
update(pos,1,n,1);
}else{
rep(i,0,K){
w[i]=-INF;
}
int x,y;
scanf("%d%d",&x,&y);
query_max(x,y,1,n,1);
int ans=-INF;
rep(i,0,K){
ans=max(ans,w[i]+w[i^K]);
}
printf("%d\n",ans);
}
}
return 0;
}
题意
思路
#include<cstdio>
#include<cstring>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define lson rt<<1
#define rson rt<<1|1
typedef long long ll;
const int MAXN=2e5+10;
int a[MAXN],b[MAXN],ans[MAXN];
int tree[MAXN<<2];
void push_up(int rt){
tree[rt]=tree[lson]+tree[rson];
}
void build(int l,int r,int rt){
if(l==r){
tree[rt]=1;
return;
}
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
push_up(rt);
}
void update(int pos,int l,int r,int rt){
if(l==r){
tree[rt]--;
return;
}
int mid=(l+r)>>1;
if(pos<=mid)update(pos,l,mid,lson);
else update(pos,mid+1,r,rson);
push_up(rt);
}
int findpos(int v,int l,int r,int rt){
if(l==r){
return r;
}
int mid=(l+r)>>1;
if(tree[lson]>=v)return findpos(v,l,mid,lson);
else return findpos(v-tree[lson],mid+1,r,rson);
}
int main(){
int n;
while(~scanf("%d",&n)){
build(1,n,1);
rep(i,1,n){
scanf("%d%d",&a[i],&b[i]);
a[i]++;
}
per(i,n,1){
int pos=findpos(a[i],1,n,1);
ans[pos]=b[i];
update(pos,1,n,1);
}
rep(i,1,n){
printf("%d ",ans[i]);
}
puts("");
}
return 0;
}
题意
#include<cstdio>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lson rt<<1
#define rson rt<<1|1
const int MAXN=5e5+10;
int cnt[MAXN],w[MAXN],a[MAXN];
char name[MAXN][15];
int tree[MAXN<<2];
void push_up(int rt){
tree[rt]=tree[lson]+tree[rson];
}
void build(int l,int r,int rt){
if(l==r){
tree[rt]=1;
return;
}
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
push_up(rt);
}
void update(int pos,int l,int r,int rt){
if(l==r){
tree[rt]--;
return;
}
int mid=(l+r)>>1;
if(pos<=mid)update(pos,l,mid,lson);
else update(pos,mid+1,r,rson);
push_up(rt);
}
int query(int v,int l,int r,int rt){
if(l==r){
return l;
}
int mid=(l+r)>>1;
if(tree[lson]>=v)return query(v,l,mid,lson);
else return query(v-tree[lson],mid+1,r,rson);
}
int main(){
rep(i,1,500000){
for(int j=i;j<=500000;j+=i){
cnt[j]++;
}
}
w[1]=1;
rep(i,2,500000){
if(cnt[i]>cnt[w[i-1]]){
w[i]=i;
}else{
w[i]=w[i-1];
}
}
int n,m;
while(~scanf("%d%d",&n,&m)){
build(1,n,1);
rep(i,1,n){
scanf("%s%d",name[i],&a[i]);
}
int k=w[n];
int now=m;
int pos=m;
rep(i,1,k){
if(i==k){
printf("%s %d\n",name[pos],cnt[k]);
break;
}
update(pos,1,n,1);
if(a[pos]>0){
now=(now-1+a[pos]-1)%tree[1]+1;
}else{
now=(now-(-a[pos])%tree[1]);
while(now<=0)now+=tree[1];
while(now>tree[1])now-=tree[1];
}
pos=query(now,1,n,1);
}
}
return 0;
}
区间更新,线段树入门门槛,lazy思想
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lson rt<<1
#define rson rt<<1|1
const int MAXN=1e5+10;
int tree[MAXN<<2],lazy[MAXN<<2];
void push_up(int rt){
tree[rt]=tree[lson]+tree[rson];
}
void push_down(int rt,int l,int r,int mid){
if(lazy[rt]){
tree[lson]=(mid-l+1)*lazy[rt];
tree[rson]=(r-mid)*lazy[rt];
lazy[lson]=lazy[rson]=lazy[rt];
lazy[rt]=0;
}
}
void build(int l,int r,int rt){
lazy[rt]=0;
if(l==r){
tree[rt]=1;
return;
}
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
push_up(rt);
}
void update(int L,int R,int v,int l,int r,int rt){
if(L<=l&&r<=R){
tree[rt]=(r-l+1)*v;
lazy[rt]=v;
return;
}
int mid=(l+r)>>1;
push_down(rt,l,r,mid);
if(mid>=L)update(L,R,v,l,mid,lson);
if(mid+1<=R)update(L,R,v,mid+1,r,rson);
push_up(rt);
}
int main(){
int T;
scanf("%d",&T);
rep(kase,1,T){
int n,q;
scanf("%d%d",&n,&q);
build(1,n,1);
while(q--){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
update(x,y,z,1,n,1);
}
printf("Case %d: The total value of the hook is %d.\n",kase,tree[1]);
}
return 0;
}
#include<cstdio>
using namespace std;
#define lson rt<<1
#define rson rt<<1|1
typedef long long ll;
const int MAXN=1e5+10;
ll tree[MAXN<<2],lazy[MAXN<<2];
void push_up(int rt){
tree[rt]=tree[lson]+tree[rson];
}
void push_down(int rt,int l,int r,int mid){
if(lazy[rt]){
tree[lson]+=lazy[rt]*(mid-l+1);
tree[rson]+=lazy[rt]*(r-mid);
lazy[lson]+=lazy[rt];
lazy[rson]+=lazy[rt];
lazy[rt]=0;
}
}
void build(int l,int r,int rt){
if(l==r){
scanf("%lld",&tree[rt]);
return;
}
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
push_up(rt);
}
void update(int L,int R,ll v,int l,int r,int rt){
if(L<=l&&r<=R){
tree[rt]+=v*(r-l+1);
lazy[rt]+=v;
return;
}
int mid=(l+r)>>1;
push_down(rt,l,r,mid);
if(mid>=L)update(L,R,v,l,mid,lson);
if(mid+1<=R)update(L,R,v,mid+1,r,rson);
push_up(rt);
}
ll query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return tree[rt];
}
int mid=(l+r)>>1;
push_down(rt,l,r,mid);
ll res=0;
if(mid>=L)res+=query(L,R,l,mid,lson);
if(mid+1<=R)res+=query(L,R,mid+1,r,rson);
return res;
}
int main(){
int n,q;
scanf("%d%d",&n,&q);
build(1,n,1);
while(q--){
char op[5];
scanf("%s",op);
if(op[0]=='Q'){
int x,y;
scanf("%d%d",&x,&y);
printf("%lld\n",query(x,y,1,n,1));
}else{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
update(x,y,z,1,n,1);
}
}
return 0;
}
题意
思路
#include<cstdio>
#include<algorithm>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lson rt<<1
#define rson rt<<1|1
const int MAXN=2e4+10;
struct node{
int v,id;
}no[MAXN];
bool cmp1(node x,node y){
return x.v<y.v;
}
int a[MAXN];
int tree[MAXN<<2];
bool vis[MAXN];
int ans;
void push_down(int rt){
if(tree[rt]==0)return;
tree[lson]=tree[rson]=tree[rt];
tree[rt]=0;
}
void build(int l,int r,int rt){
tree[rt]=0;
if(l==r){
return;
}
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
}
void update(int L,int R,int v,int l,int r,int rt){
if(L<=l&&r<=R){
tree[rt]=v;
return;
}
push_down(rt);
int mid=(l+r)>>1;
if(mid>=L)update(L,R,v,l,mid,lson);
if(mid+1<=R)update(L,R,v,mid+1,r,rson);
}
void query(int l,int r,int rt){
if(tree[rt]){
if(!vis[tree[rt]]){
vis[tree[rt]]=true;
ans++;
}
return;
}
if(l==r){
return;
}
int mid=(l+r)>>1;
query(l,mid,lson);
query(mid+1,r,rson);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
rep(i,1,n){
scanf("%d%d",&no[i].v,&no[i+n].v);
no[i].id=i;
no[i+n].id=i+n;
}
sort(no+1,no+1+2*n,cmp1);
int cnt=1;
a[no[1].id]=1;
rep(i,2,2*n){
if(no[i].v!=no[i-1].v){
cnt++;
}
a[no[i].id]=cnt;
}
build(1,cnt,1);
rep(i,1,n){
update(a[i],a[i+n],i,1,cnt,1);
vis[i]=false;
}
ans=0;
query(1,cnt,1);
printf("%d\n",ans);
}
return 0;
}
#include<cstdio>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lson rt<<1
#define rson rt<<1|1
const int MAXN=65535*2+1;
int tree[MAXN<<2];
int ans[MAXN];
void change(int &x){
if(x==0)x=3;
else if(x==3)x=0;
else x=3-x;
}
void push_down(int rt){
if(tree[rt]==1||tree[rt]==2){
tree[lson]=tree[rson]=tree[rt];
tree[rt]=0;
}else if(tree[rt]==3){
change(tree[lson]);
change(tree[rson]);
tree[rt]=0;
}
}
void update1(int L,int R,int v,int l,int r,int rt){
if(L<=l&&r<=R){
tree[rt]=v;
return;
}
if(l==r)return;
int mid=(l+r)>>1;
push_down(rt);
if(mid>=L)update1(L,R,v,l,mid,lson);
if(mid+1<=R)update1(L,R,v,mid+1,r,rson);
}
void update2(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
change(tree[rt]);
return;
}
if(l==r)return;
int mid=(l+r)>>1;
push_down(rt);
if(mid>=L)update2(L,R,l,mid,lson);
if(mid+1<=R)update2(L,R,mid+1,r,rson);
}
void query(int l,int r,int rt){
if(tree[rt]==1){
rep(i,l,r)ans[i]=1;
}else if(tree[rt]==2){
return;
}
if(l==r){
return;
}
int mid=(l+r)>>1;
push_down(rt);
query(l,mid,lson);
query(mid+1,r,rson);
}
void check(){
query(0,MAXN,1);
rep(i,0,30){
if(i&1)printf("%d ",ans[i]);
else printf("%d",ans[i]);
}
puts("");
}
int main(){
char op[5];
tree[1]=2;
while(~scanf("%s",op)){
if(op[0]=='z')break;
getchar();
char a,b;
int x,y;
scanf("%c%d,%d%c",&a,&x,&y,&b);
if(a=='['){
x=x*2;
}else{
x=x*2+1;
}
if(b==']'){
y=y*2;
}else{
y=y*2-1;
}
if(op[0]=='U'){
if(x<=y)update1(x,y,1,0,MAXN,1);
}else if(op[0]=='I'){
if(x>0)update1(0,x-1,2,0,MAXN,1);
if(y<MAXN)update1(y+1,MAXN,2,0,MAXN,1);
}else if(op[0]=='D'){
if(x<=y)update1(x,y,2,0,MAXN,1);
}else if(op[0]=='C'){
if(x>0)update1(0,x-1,2,0,MAXN,1);
if(y<MAXN)update1(y+1,MAXN,2,0,MAXN,1);
if(x<=y)update2(x,y,0,MAXN,1);
}else{
if(x<=y)update2(x,y,0,MAXN,1);
}
}
query(0,MAXN,1);
bool f=false;
int l=-1;
rep(i,0,MAXN+1){
if(ans[i]==1){
f=true;
if(l==-1){
l=i;
}
}else{
if(l!=-1){
if(l&1){
printf("(%d,",l>>1);
}else{
printf("[%d,",l>>1);
}
if((i-1)&1){
printf("%d) ",i>>1);
}else{
printf("%d] ",i>>1);
}
l=-1;
}
}
}
if(!f)puts("empty set");
return 0;
}
题意
- 给出若干竖直的线段,问有多少三元组,三个线段相互可见
思路
- 先用线段树预处理出两两间是否可见,然后三重循环暴力解出,注意虽然是三重循环但复杂度是n2 而不是n3。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lson rt<<1
#define rson rt<<1|1
const int MAXN=8000+10;
struct node{
int y1,y2,x;
node(){}
node(int y1,int y2,int x):
y1(y1),y2(y2),x(x){}
}no[MAXN];
bool cmp(node a,node b){
return a.x<b.x;
}
bool vis[MAXN][MAXN];
int tree[MAXN<<3];
void push_down(int rt){
if(tree[rt]){
tree[lson]=tree[rson]=tree[rt];
tree[rt]=0;
}
}
void build(int l,int r,int rt){
tree[rt]=0;
if(l==r){
return;
}
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
}
void query(int L,int R,int v,int l,int r,int rt){
if(tree[rt]){
vis[v][tree[rt]]=true;
vis[tree[rt]][v]=true;
return;
}
if(l==r)return;
int mid=(l+r)>>1;
push_down(rt);
if(mid>=L)query(L,R,v,l,mid,lson);
if(mid+1<=R)query(L,R,v,mid+1,r,rson);
}
void update(int L,int R,int v,int l,int r,int rt){
if(L<=l&&r<=R){
tree[rt]=v;
return;
}
int mid=(l+r)>>1;
push_down(rt);
if(mid>=L)update(L,R,v,l,mid,lson);
if(mid+1<=R)update(L,R,v,mid+1,r,rson);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
memset(vis,0,sizeof(vis));
int n;
scanf("%d",&n);
rep(i,1,n){
int y1,y2,x;
scanf("%d%d%d",&y1,&y2,&x);
no[i]=node(y1<<1,y2<<1,x);
}
sort(no+1,no+1+n,cmp);
build(0,16000,1);
rep(i,1,n){
query(no[i].y1,no[i].y2,i,0,16000,1);
update(no[i].y1,no[i].y2,i,0,16000,1);
}
int ans=0;
rep(i,1,n){
rep(j,i+1,n){
if(vis[i][j]){
rep(k,j+1,n){
if(vis[i][k]&&vis[j][k]){
ans++;
}
}
}
}
}
printf("%d\n",ans);
}
return 0;
}
其他好题