高级数据结构模板
线段树
维护区间最值
struct node{
int l,r;
ll ma,mi;
}t[maxn];
ll a[maxn];
int n,m;
void build(int p,int l,int r){
t[p].l=l;
t[p].r=r;
if(l==r){
t[p].ma=t[p].mi=a[l];
return ;
}
int mid=(t[p].l+t[p].r)/2;
build(2*p,l,mid);
build(2*p+1,mid+1,r);
t[p].ma=max(t[2*p].ma,t[2*p+1].ma);
t[p].mi=min(t[2*p].mi,t[2*p+1].mi);
}
ll query_max(int p,int l,int r){
if(t[p].l>=l&&t[p].r<=r){
return t[p].ma;
}
ll ma=0;
int mid=(t[p].l+t[p].r)/2;
if(l<=mid){
ma=max(ma,query_max(2*p,l,r));
}
if(r>mid){
ma=max(ma,query_max(2*p+1,l,r));
}
return ma;
}
ll query_min(int p,int l,int r){
if(t[p].l>=l&&t[p].r<=r){
return t[p].mi;
}
ll mi=1e18;
int mid=(t[p].l+t[p].r)/2;
if(l<=mid){
mi=min(mi,query_min(2*p,l,r));
}
if(r>mid){
mi=min(mi,query_min(2*p+1,l,r));
}
return mi;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
build(1,1,n);
int l,r;
for(int i=1;i<=m;i++){
scanf("%d%d",&l,&r);
printf("%lld\n",query_max(1,l,r)-query_min(1,l,r));
}
}
区间最值&&最值个数
int a[maxn];
struct node{
int l,r;
int ma,cnt;
}t[maxn];
int ans1,n,m,x,y;
void push_up(int p){
t[p].ma=max(t[2*p].ma,t[2*p+1].ma);
if(t[2*p].ma==t[2*p+1].ma){
t[p].cnt=t[2*p].cnt+t[2*p+1].cnt;
}
else if(t[2*p].ma>t[2*p+1].ma){
t[p].cnt=t[2*p].cnt;
}
else{
t[p].cnt=t[2*p+1].cnt;
}
}
void build(int p,int l,int r){
t[p].l=l;
t[p].r=r;
t[p].cnt=0;
if(l==r){
t[p].ma=a[l];
t[p].cnt=1;
return ;
}
int mid=(l+r)/2;
build(2*p,l,mid);
build(2*p+1,mid+1,r);
push_up(p);
}
void update(int p,int x,int k){
if(t[p].l==t[p].r){
t[p].ma=k;
t[p].cnt=1;
return ;
}
int mid=(t[p].l+t[p].r)/2;
if(x<=mid){
update(2*p,x,k);
}
else{
update(2*p+1,x,k);
}
push_up(p);
}
void query(int p,int l,int r){
int L=t[p].l,R=t[p].r;
if(L>=l&&R<=r){
ans1=max(ans1,t[p].ma);
return ;
}
int mid=(L+R)/2;
if(l<=mid){
query(2*p,l,r);
}
if(r>mid){
query(2*p+1,l,r);
}
push_up(p);
}
int getcnt(int p,int l,int r){
int L=t[p].l,R=t[p].r;
if(L>=l&&R<=r&&t[p].cnt){
if(ans1==t[p].ma){
return t[p].cnt;
}
else return 0;
}
int z=0;
int mid=(L+R)/2;
if(l<=mid){
z+=getcnt(2*p,l,r);
}
if(r>mid){
z+=getcnt(2*p+1,l,r);
}
push_up(p);
return z;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,1,n);
char str[maxn];
for(int i=1;i<=m;i++){
cin>>str>>x>>y;
if(str[0]=='A'){
ans1=0;
query(1,x,y);
printf("%d %d\n",ans1,getcnt(1,x,y));
}
else{
update(1,x,y);
}
}
}
区间求和&&区间查询
struct node{
ll l,r;
ll s;
ll lazy;
}t[maxn];
ll a[maxn];
int n,m;
void push(int p){
t[2*p].lazy+=t[p].lazy;//下传标记
t[2*p].s+=1ll*(t[2*p].r-t[2*p].l+1)*t[p].lazy;
t[2*p+1].lazy+=t[p].lazy;
t[2*p+1].s+=1ll*(t[2*p+1].r-t[2*p+1].l+1)*t[p].lazy;
t[p].lazy=0;//还原标记
}
void build(int p,int l,int r){
t[p].l=l;
t[p].r=r;
if(l==r){
t[p].s=a[l];
return ;
}
int mid=(l+r)/2;
build(2*p,l,mid);
build(2*p+1,mid+1,r);
t[p].s=t[2*p].s+t[2*p+1].s;
}
void update(int p,int l,int r,ll k){
int L=t[p].l,R=t[p].r;
if(L>=l&&R<=r){
t[p].s+=1ll*(R-L+1)*k;
t[p].lazy+=k;
return ;
}
push(p);
if(l<=t[2*p].r){
update(2*p,l,r,k);
}
if(r>=t[2*p+1].l){
update(2*p+1,l,r,k);
}
t[p].s=t[2*p].s+t[2*p+1].s;
}
ll query(int p,int l,int r){
int L=t[p].l,R=t[p].r;
if(L>r||R<l){
return 0;
}
if(l<=L&&r>=R){
return t[p].s;
}
ll ans=0;
push(p);
if(l<=t[2*p].r){
ans+=query(2*p,l,r);
}
if(r>=t[2*p+1].l){
ans+=query(2*p+1,l,r);
}
return ans;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
build(1,1,n);
char str[10];
int l,r;
ll k;
for(int i=1;i<=m;i++){
scanf("%s",str);
if(str[0]=='Q'){
scanf("%d%d",&l,&r);
ll ans=query(1,l,r);
printf("%lld\n",ans);
}
else if(str[0]=='C'){
scanf("%d%d%lld",&l,&r,&k);
update(1,l,r,k);
}
}
return 0;
}
线段树乘法
ll a[maxn];
ll mod;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
struct node{
ll l;//l:左节点 r:右节点
ll r;//dat:当前节点的值 laze_tag:懒标记,记录改变的值,递归传值
ll date,laze;
ll mul;
}t[maxn];//四倍n
//void f(ll p,ll m,ll k){
// t[p].laze=(t[p].laze*m+k)%mod;//懒标记传递
// t[p].date+=(k*(t[p].r-t[p].l+1))%mod;//当前值加上所有节点总数*值
//}
//void fmul(ll p,ll k){
// t[p].mul=(t[p].mul*k)%mod;
// t[p].date+=(t[p].date*k)%mod;
//}
//void pushdown(ll p){//传懒标
// f(p*2,t[p].mul,t[p].laze);
// f(p*2+1,t[p].mul,t[p].laze);
// fmul(p*2,t[p].mul);
// fmul(p*2+1,t[p].mul);
// //将懒标记的值传给下面的左右儿子节点
// t[p].laze=0;
// t[p].mul=1;
// //复原懒标记
//}
void pushdown(ll x)
{
t[x*2].laze=(t[x*2].laze*t[x].mul+t[x].laze)%mod;//加
t[x*2+1].laze=(t[x*2+1].laze*t[x].mul+t[x].laze)%mod;
t[x*2].mul=(t[x*2].mul*t[x].mul)%mod;//乘
t[x*2+1].mul=(t[x*2+1].mul*t[x].mul)%mod;
t[x*2].date=(t[x].laze*(t[x*2].r-t[x*2].l+1)%mod+t[x*2].date*t[x].mul%mod)%mod;//求和
t[x*2+1].date=(t[x].laze*(t[x*2+1].r-t[x*2+1].l+1)%mod+t[x*2+1].date*t[x].mul%mod)%mod;//求和
t[x].laze=0;t[x].mul=1;
}
void js(ll p,ll l,ll r){//建树
t[p].l=l;//记录左右节点
t[p].r=r;
t[p].laze=0;
t[p].mul=1;
if(l==r){//到达底部返回值
t[p].date=a[l];
return ;
}
ll mid=(l+r)/2;//中点
js(p*2,l,mid);
js(p*2+1,mid+1,r);
//递归初始化
t[p].date=(t[p*2].date+t[p*2+1].date)%mod;
//加上左右儿子节点
}
void pushs(ll p,ll l,ll r,ll v){//区间加减
if(t[p].l>=l&&t[p].r<=r){//如果区间被包含就修改并打上懒标记
t[p].date+=v*(t[p].r-t[p].l+1)%mod;//加上所有值
t[p].laze+=v%mod;//懒标记修改
return ;
}
pushdown(p);//查询懒标记,因为下面要递归
ll mid=(t[p].l+t[p].r)/2;//取中点
if(l<=mid){
pushs(p*2,l,r,v);//修改左边
}
if(r>mid){
pushs(p*2+1,l,r,v);//修改右边
}
t[p].date=(t[p*2].date+t[p*2+1].date)%mod;//回溯时加上左右儿子节点的值
}
void cheng(ll p,ll l,ll r,ll w){
if(l<=t[p].l&&t[p].r<=r){
t[p].date=t[p].date*w%mod;
t[p].laze=t[p].laze*w%mod;
t[p].mul=t[p].mul*w%mod;
return ;
}
pushdown(p);
ll mid=(t[p].l+t[p].r)/2;//取中点
if(l<=mid){
cheng(p*2,l,r,w);//修改左边
}
if(r>mid){
cheng(p*2+1,l,r,w);//修改右边
}
t[p].date=(t[p*2].date+t[p*2+1].date)%mod;
}
//void cheng(ll x,ll l,ll r,ll d)
//{
// if (l<=t[x].l&&t[x].r<=r)//全部包括
//{//三个值全部都要乘上去
//
// t[x].date=t[x].date*d%mod;
// t[x].laze=t[x].laze*d%mod;
// t[x].mul=t[x].mul*d%mod;
// } else
// {
// pushdown(x);//向下传递值
// ll mid=(t[x].l+t[x].r)/2;
// if (l<=mid) cheng(x*2,l,r,d);//继续往下搜
// if (r>mid)cheng(x*2+1,l,r,d);
// t[x].date=(t[x*2+1].date+t[x*2].date)%mod;//更新sum
// }
// return;
//}
ll outt(ll p,ll l){//单点查询
if(t[p].l==l&&t[p].r==l){//找到目标点就返回
return t[p].date%mod;
}
pushdown(p);//先回复懒标记的值再传递,因为下面可能递归(要判断是否到了底部,就是这里出了问题QwQ)
ll mid=(t[p].l+t[p].r)/2;//记录中点
if(l<=mid) return outt(p*2,l)%mod;//找左边
if(l>mid) return outt(p*2+1,l)%mod;//找右边
}
ll check(ll p,ll l,ll r,ll x,ll y){
if(l>=x&&r<=y){
return t[p].date%mod;
}
ll mid=(t[p].l+t[p].r)/2;
ll ans=0;
pushdown(p);
if(x<=mid){
ans+=check(p*2,l,mid,x,y)%mod;
}
if(mid<y){
ans+=check(p*2+1,mid+1,r,x,y)%mod;
}
return ans%mod;
}
int main(){
int n,m;
cin>>n>>m>>mod;//读入
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
js(1,1,n);//建树
ll z;
ll x,y,w;
for(int i=1;i<=m;i++){
scanf("%lld",&z);
if(z==1){
scanf("%lld%lld%lld",&x,&y,&w);
cheng(1,x,y,w);
}
else if(z==2){
scanf("%lld%lld%lld",&x,&y,&w);
pushs(1,x,y,w);
}
else if(z==3){
scanf("%lld%lld",&x,&y);
ll ans=check(1,1,n,x,y)%mod;
printf("%lld\n",ans%mod);
}
}
return 0;//华丽丽的结束,可以A掉树状数组2了!!!
线段树01转换
const int maxn=5e6+100;
struct node{
int l,r;
int s;
int lazy;
}t[maxn];
void build(int p,int l,int r){
t[p].l=l;
t[p].r=r;
if(l==r){
return ;
}
int mid=(l+r)/2;
build(2*p,l,mid);
build(2*p+1,mid+1,r);
}
void push(int p){
if(t[p].lazy){
t[2*p].s=(t[2*p].r-t[2*p].l+1)-t[2*p].s;
t[2*p+1].s=(t[2*p+1].r-t[2*p+1].l+1)-t[2*p+1].s;
t[2*p].lazy^=1;
t[2*p+1].lazy^=1;
t[p].lazy=0;
}
}
void update(int p,int l,int r){
if(t[p].l>=l&&t[p].r<=r){
t[p].s=t[p].r-t[p].l+1-t[p].s;
t[p].lazy^=1;
return ;
}
if(t[p].lazy) push(p);
int mid=(t[p].l+t[p].r)/2;
if(l<=mid){
update(2*p,l,r);
}
if(r>mid){
update(2*p+1,l,r);
}
t[p].s=t[2*p].s+t[2*p+1].s;
}
int query(int p,int l,int r){
if(t[p].l>=l&&t[p].r<=r){
return t[p].s;
}
int ans=0;
if(t[p].lazy) push(p);
int mid=(t[p].l+t[p].r)/2;
if(l<=mid){
ans+=query(2*p,l,r);
}
if(r>mid){
ans+=query(2*p+1,l,r);
}
return ans;
}
int n,m;
int main(){
cin>>n>>m;
int op,x,y;
build(1,1,n);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&op,&x,&y);
if(op==0){
update(1,x,y);
}
else if(op==1){
printf("%d\n",query(1,x,y));
}
}
}
树状数组
单点修改&&区间查询
要是想减去一个数的话就是加上一个负数
int a[maxn],c[maxn];
int lowbit(int x){
return x&-x;
}
int add(int x,int k){
for(int i=x;i<=n;i+=lowbit(i)){
c[i]+=k;
}
}
int getsum(int x){
ll ans=0;
for(int i=x;i>0;i-=lowbit(i)){
ans+=c[i];
}
return ans;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
add(i,a[i]);
}
int op;
int x,y;ll k;
for(int i=1;i<=m;i++){
scanf("%d",&op);
if(op==1){
scanf("%d%lld",&x,&k);
add(x,k);
}
else if(op==2){
scanf("%d%d",&x,&y);
printf("%lld\n",getsum(y)-getsum(x-1));
}
}
区间修改&&单点查询
ll a[maxn];
ll c[maxn];
int lowbit(int x){
return x&-x;
}
void add(int x,ll k){
for(int i=x;i<=n;i+=lowbit(i)){
c[i]+=k;
}
}
ll getsum(int x){
ll ans=0;
for(int i=x;i>0;i-=lowbit(i)){
ans+=c[i];
}
return ans;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
add(i,a[i]-a[i-1]);
}
int op,a,b;
ll k;
while(m--){
scanf("%d",&op);
if(op==1){
scanf("%d%d%lld",&a,&b,&k);
add(a,k);
add(b+1,-k);
}
else if(op==2){
scanf("%d",&a);
printf("%lld\n",getsum(a));
}
}
return 0;
}
区间修改&&区间查询
ll a[maxn];
ll lowbit(int x){
return x&-x;
}
int n,m;
ll sum1[maxn],sum2[maxn];
void add(int x,ll k){
for(int i=x;i<=n;i+=lowbit(i)){
sum1[i]+=k;
sum2[i]+=1ll*k*(x-1);
}
}
ll query(int x){
ll ans=0;
for(int i=x;i>0;i-=lowbit(i)){
ans+=1ll*x*sum1[i]-sum2[i];
}
return ans;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
add(i,a[i]-a[i-1]);
}
char str[10];
int l,r,x;
ll k;
for(int i=1;i<=m;i++){
scanf("%s",str);
if(str[0]=='Q'){
scanf("%d%d",&l,&r);
printf("%lld\n",query(r)-query(l-1));
}
else if(str[0]=='C'){
scanf("%d%d%lld",&l,&r,&k);
add(l,k);
add(r+1,-k);
}
}
字典树
01字典树
给定的 n个数中选出两个来异或,得到的结果最大是多少?
const int maxn=4e6+100;
int a[maxn];
int t[maxn][3];
int cnt[maxn];
int idx;
void insert(int x){
int root=0;
for(int i=30;i>=0;i--){
int p=(x>>i)&1;
if(!t[root][p]){
t[root][p]=++idx;
}
root=t[root][p];
cnt[root]++;
}
}
int query(int x){
int ans=0;
int root=0;
for(int i=30;i>=0;i--){
int p=(x>>i)&1;
if(t[root][!p]){
ans+=(1<<i);
root=t[root][!p];
}
else{
root=t[root][p];
}
}
return ans;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int ans=0;
insert(a[1]);
for(int i=2;i<=n;i++){
ans=max(ans,query(a[i]));
insert(a[i]);
}
printf("%d",ans);
}
字典树模板题
int a[maxn][26];
int k[maxn];
bool vis[maxn];
char t[maxn];
int cnt;
void build(){
int p=0;
for(int i=0;i<strlen(t);i++){
int c=t[i]-'a';
if(!a[p][c]){ a[p][c]=++cnt;};
p=a[p][c];
k[p]++;
}
vis[p]=1;
}
int query(){
int ans=0;
int p=0;
for(int i=0;i<strlen(t);i++){
int c=t[i]-'a';
if(!a[p][c]) return 0;
p=a[p][c];
}
return k[p];
}
int main(){
while(gets(t)){
int len=strlen(t);
if(len==0){
break;
}
build();
}
while(gets(t)){
int ans=query();
cout<<ans<<endl;
}
}