今天是2017/5/23,DCDCBigBig的第十一篇博文
啊。。。昨天真是太累了。。。把樹鏈剖分先傳上來了,用的還是線段樹區間修改。然而我並沒有傳線段樹。。。(所以說那份代碼是py來的。。。)那這篇博文就多放點模板,給大家發發福利吧^_^
線段樹1(單點修改)
//求區間最值
//n個元素,m個詢問
//C x y 代表將第x個元素的值改爲y
//D x y 代表在第x到第y個元素中找最大值
//X x y 代表在第x到第y個元素中找最小值
//附帶一個print函數,可以遍歷並輸出葉節點
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
struct tree_node{
int maxn,minn;
}t[400001];
int n,m,x,y,a[100001];
char ord[5];
void build(int l,int r,int u){
if(l==r){
t[u].maxn=a[l];
t[u].minn=a[l];
return;
}
int mid=(l+r)/2;
build(l,mid,u*2);
build(mid+1,r,u*2+1);
t[u].maxn=max(t[u*2].maxn,t[u*2+1].maxn);
t[u].minn=min(t[u*2].minn,t[u*2+1].minn);
}
void print(int l,int r,int u){
if(l==r){
printf("%d ",t[u].minn);
return;
}
int mid=(l+r)/2;
print(l,mid,u*2);
print(mid+1,r,u*2+1);
}
void updata(int l,int r,int u,int x,int y){
if(l==r){
t[u].maxn=y;
t[u].minn=y;
return;
}
int mid=(l+r)/2;
if(x<=mid)updata(l,mid,u*2,x,y);
else if(x>mid)updata(mid+1,r,u*2+1,x,y);
t[u].maxn=max(t[u*2].maxn,t[u*2+1].maxn);
t[u].minn=min(t[u*2].minn,t[u*2+1].minn);
}
int query_max(int l,int r,int u,int L,int R){
if(l>=L&&r<=R){
return t[u].maxn;
}
int mid=(l+r)/2,ans=-2147483647;
if(L<=mid)ans=max(ans,query_max(l,mid,u*2,L,R));
if(R>mid)ans=max(ans,query_max(mid+1,r,u*2+1,L,R));
return ans;
}
int query_min(int l,int r,int u,int L,int R){
if(l>=L&&r<=R){
return t[u].minn;
}
int mid=(l+r)/2,ans=2147483647;
if(L<=mid)ans=min(ans,query_min(l,mid,u*2,L,R));
if(R>mid)ans=min(ans,query_min(mid+1,r,u*2+1,L,R));
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,n,1);
for(int i=1;i<=m;i++){
scanf("%s",ord);
if(ord[0]=='P'){
print(1,n,1);
printf("\n");
continue;
}
scanf("%d%d",&x,&y);
if(ord[0]=='C'){
updata(1,n,1,x,y);
}
if(ord[0]=='D'){
printf("%d\n",query_max(1,n,1,x,y));
}
if(ord[0]=='X'){
printf("%d\n",query_min(1,n,1,x,y));
}
}
return 0;
}
線段樹2(區間修改+lazy標記)
區間加值
ps:懶癌發作,不知道拖了幾天才寫好。。。
//區間求和+區間修改(區間加值版)
//類似地,n個元素、m個詢問
//Q x y表示詢問x至y的和
//A x y z表示將x到y的值全部加上z
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
struct tree{
int v,lazy;
}t[400001];
int n,m,x,y,z,a[100001];
char ord[5];
void pd(int u,int l,int r){
if(t[u].lazy!=0){
int mid=(l+r)/2;
t[u*2].lazy+=t[u].lazy;
t[u*2+1].lazy+=t[u].lazy;
t[u*2].v+=t[u].lazy*(mid-l+1);
t[u*2+1].v+=t[u].lazy*(r-mid);
t[u].lazy=0;
}
}
void build(int l,int r,int u){
if(l==r){
t[u].v=a[l];
return;
}
int mid=(l+r)/2;
t[u].lazy=0;
build(l,mid,u*2);
build(mid+1,r,u*2+1);
t[u].v=t[u*2].v+t[u*2+1].v;
}
void updata(int l,int r,int u,int L,int R,int val){
if(L<=l&&r<=R){
t[u].lazy+=val;
t[u].v+=val*(r-l+1);
return;
}
pd(u,l,r);
int mid=(l+r)/2;
if(L<=mid)updata(l,mid,u*2,L,R,val);
if(R>mid)updata(mid+1,r,u*2+1,L,R,val);
t[u].v=t[u*2].v+t[u*2+1].v;
}
int query(int l,int r,int u,int L,int R){
if(L<=l&&r<=R){
return t[u].v;
}
pd(u,l,r);
int mid=(l+r)/2,ans=0;
if(L<=mid)ans+=query(l,mid,u*2,L,R);
if(R>mid)ans+=query(mid+1,r,u*2+1,L,R);
t[u].v=t[u*2].v+t[u*2+1].v;
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,n,1);
for(int i=1;i<=m;i++){
scanf("%s%d%d",ord,&x,&y);
if(ord[0]=='A'){
scanf("%d",&z);
updata(1,n,1,x,y,z);
}
if(ord[0]=='Q'){
printf("%d\n",query(1,n,1,x,y));
}
}
return 0;
}
/*
5 5
1 2 3 4 5
Q 1 5
A 1 3 5
Q 1 5
A 3 5 -3
Q 1 5
*/
區間改值
//區間求和+區間修改(區間改值版)
//n個元素、m個詢問
//Q x y表示詢問x至y的和
//C x y z表示將x到y的值全部改成z
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
struct tree{
int v,lazy;
}t[400001];
int n,m,x,y,z,a[100001];
char ord[5];
void pd(int u,int l,int r){
if(t[u].lazy!=0){
int mid=(l+r)/2;
t[u*2].lazy=t[u].lazy;
t[u*2+1].lazy=t[u].lazy;
t[u*2].v=t[u].lazy*(mid-l+1);
t[u*2+1].v=t[u].lazy*(r-mid);
t[u].lazy=0;
}
}
void build(int l,int r,int u){
if(l==r){
t[u].v=a[l];
return;
}
int mid=(l+r)/2;
t[u].lazy=0;
build(l,mid,u*2);
build(mid+1,r,u*2+1);
t[u].v=t[u*2].v+t[u*2+1].v;
}
void updata(int l,int r,int u,int L,int R,int val){
if(L<=l&&r<=R){
t[u].lazy=val;
t[u].v=val*(r-l+1);
return;
}
pd(u,l,r);
int mid=(l+r)/2;
if(L<=mid)updata(l,mid,u*2,L,R,val);
if(R>mid)updata(mid+1,r,u*2+1,L,R,val);
t[u].v=t[u*2].v+t[u*2+1].v;
}
int query(int l,int r,int u,int L,int R){
if(L<=l&&r<=R){
return t[u].v;
}
pd(u,l,r);
int mid=(l+r)/2,ans=0;
if(L<=mid)ans+=query(l,mid,u*2,L,R);
if(R>mid)ans+=query(mid+1,r,u*2+1,L,R);
t[u].v=t[u*2].v+t[u*2+1].v;
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,n,1);
for(int i=1;i<=m;i++){
scanf("%s%d%d",ord,&x,&y);
if(ord[0]=='C'){
scanf("%d",&z);
updata(1,n,1,x,y,z);
}
if(ord[0]=='Q'){
printf("%d\n",query(1,n,1,x,y));
}
}
return 0;
}
/*
5 5
1 2 3 4 5
Q 1 5
C 1 3 5
Q 1 5
C 3 5 -3
Q 1 5
*/
可持久化線段樹(單點修改)
//單點修改可持久化線段樹(非主席樹)
//給出n個數,q個詢問
//每次詢問形如 0 k l r 或 1 k i x
//表示詢問第k個版本l到r之間的最大值或把第k個版本的第i個數改爲x
//初始的n個數表示第一個版本
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
struct node{
int mx,ls,rs;
}t[2000001];
int n,q,k,l,r,ord,cnt=0,tot=0,rt[100001],num[100001];
void build(int l,int r,int &u){
if(!u)u=++tot;
if(l==r){
t[u].mx=num[l];
return;
}
int mid=(l+r)/2;
build(l,mid,t[u].ls);
build(mid+1,r,t[u].rs);
t[u].mx=max(t[t[u].ls].mx,t[t[u].rs].mx);
}
void ins(int &k,int last,int l,int r,int p,int x){
t[k=++tot].mx=t[last].mx;
if(l==r){
t[k].mx=x;
return;
}
t[k].ls=t[last].ls;
t[k].rs=t[last].rs;
int mid=(l+r)/2;
if(p<=mid)ins(t[k].ls,t[last].ls,l,mid,p,x);
else ins(t[k].rs,t[last].rs,mid+1,r,p,x);
t[k].mx=max(t[t[k].ls].mx,t[t[k].rs].mx);
}
int query(int &k,int l,int r,int L,int R){
if(!k)return 0;
if(L==l&&r==R){
return t[k].mx;
}
int mid=(l+r)/2;
if(R<=mid)return query(t[k].ls,l,mid,L,R);
else if(L>mid)return query(t[k].rs,mid+1,r,L,R);
else return max(query(t[k].ls,l,mid,L,mid),query(t[k].rs,mid+1,r,mid+1,R));
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
}
build(1,n,rt[++cnt]);
for(int i=1;i<=q;i++){
scanf("%d%d%d%d",&ord,&k,&l,&r);
if(ord==1){
ins(rt[++cnt],rt[k],1,n,l,r);
}else{
printf("%d\n",query(rt[k],1,n,l,r));
}
}
return 0;
}
可持久化線段樹(區間修改)
//hdu4348
//標記永久化是真的省空間!!!
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
struct node{
int ls,rs;
ll v,lazy;
}t[5000001];
int n,m,k,l,r,v,tot,cnt,num[100001],rt[100001];
char ord[3];
int build(int l,int r){
int u=++tot;
t[u].lazy=0;
if(l==r){
t[u].v=num[l];
return u;
}
int mid=(l+r)/2;
t[u].ls=build(l,mid);
t[u].rs=build(mid+1,r);
t[u].v=t[t[u].ls].v+t[t[u].rs].v;
return u;
}
int rebuild(int l,int r,int L,int R,int v,int k){
int u=++tot;
t[u].v=t[k].v;
t[u].ls=t[k].ls;
t[u].rs=t[k].rs;
t[u].lazy=t[k].lazy;
if(l==L&&r==R){
t[u].lazy+=v;
t[u].v+=v*(r-l+1);
return u;
}
int mid=(l+r)/2;
if(R<=mid)t[u].ls=rebuild(l,mid,L,R,v,t[k].ls);
else if(L>mid)t[u].rs=rebuild(mid+1,r,L,R,v,t[k].rs);
else{
t[u].ls=rebuild(l,mid,L,mid,v,t[k].ls);
t[u].rs=rebuild(mid+1,r,mid+1,R,v,t[k].rs);
}
t[u].v=t[t[u].ls].v+t[t[u].rs].v;
t[u].v+=t[u].lazy*(r-l+1);
return u;
}
ll query(int l,int r,int u,int L,int R){
if(l==L&&r==R){
return t[u].v;
}
int mid=(l+r)/2;
ll ans=0;
if(L>=l&&R<=r)ans+=t[u].lazy*(R-L+1);
else if(L<l&&R>=l&&R<=r)ans+=t[u].lazy*(R-l+1);
else if(R>r&&L>=l&&L<=r)ans+=t[u].lazy*(r-L+1);
else if(L<l&&R>r)ans+=t[u].lazy*(r-l+1);
if(R<=mid)ans+=query(l,mid,t[u].ls,L,R);
else if(L>mid)ans+=query(mid+1,r,t[u].rs,L,R);
else ans+=query(l,mid,t[u].ls,L,mid)+query(mid+1,r,t[u].rs,mid+1,R);
return ans;
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
tot=cnt=0;
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
}
rt[0]=build(1,n);
for(int i=1;i<=m;i++){
scanf("%s",ord);
if(ord[0]=='C'){
scanf("%d%d%d",&l,&r,&v);
rt[cnt+1]=rebuild(1,n,l,r,v,rt[cnt]);
cnt++;
}else if(ord[0]=='Q'){
scanf("%d%d",&l,&r);
printf("%lld\n",query(1,n,rt[cnt],l,r));
}else if(ord[0]=='H'){
scanf("%d%d%d",&l,&r,&v);
printf("%lld\n",query(1,n,rt[v],l,r));
}else{
scanf("%d",&v);
cnt=v;
}
}
}
return 0;
}
主席樹求區間k大
//Orz hjt
//其實和可持久化線段是還是有點區別的QAQ
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
struct node{
int ls,rs,v;
}t[2000001];
int n,q,k,l,r,pos,tot=0,cnt=0,a[100001],b[100001],rt[100001];
int build(int l,int r){
int u=++tot;
t[u].v=0;
if(l==r)return u;
int mid=(l+r)/2;
t[u].ls=build(l,mid);
t[u].rs=build(mid+1,r);
return u;
}
int ins(int l,int r,int k,int p){
int u=++tot;
t[u].ls=t[k].ls;
t[u].rs=t[k].rs;
t[u].v=t[k].v+1;
if(l==r)return u;
int mid=(l+r)/2;
if(p<=mid)t[u].ls=ins(l,mid,t[k].ls,p);
else t[u].rs=ins(mid+1,r,t[k].rs,p);
return u;
}
int query(int l,int r,int pre,int now,int k){
if(t[now].ls==t[now].rs){
return b[l];
}
int mid=(l+r)/2,tmp=t[t[now].ls].v-t[t[pre].ls].v;
if(tmp>=k)return query(l,mid,t[pre].ls,t[now].ls,k);
else return query(mid+1,r,t[pre].rs,t[now].rs,k-tmp);
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
rt[0]=build(1,n);
//printf("a\n");
for(int i=1;i<=n;i++)rt[i]=ins(1,n,rt[i-1],lower_bound(b+1,b+n+1,a[i])-b);
for(int i=1;i<=q;i++){
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",query(1,n,rt[l-1],rt[r],k));
}
return 0;
}