hihoCoder - 1116 - 计算 (线段树区间合并)

线段树区间合并的题目套路就是每一段维护
1.当前段的答案data[k],
2.当前段所有前缀Left[k]
3.当前段所有后缀Right[k]
合并时由当前段的左右子节点的data转移当前段,
还有左子节点的后缀与右子节点的前缀合并形成的区间对当前段的贡献。
然后维护当前段Left,Right就ok了。

现在很少看见用vect或者map维护每一段前后缀的了(我会说是跑的太慢了吗)。
一般都会用组合数学优化一下或者二进制优化。
这里也不例外,当前段的每一个前后缀都是乘积Left,Right只是这些前后缀的和,

合并原理类似多项式乘法,(和的乘积等于两个多项式的乘积)


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <map>
#define mid (l+r>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
using namespace std;
const int mod=10007;
const int maxn=1e5+7;
int data[maxn*4];
int Len[maxn*4];
int Left[maxn*4],Right[maxn*4];

void update(int k,int l,int r,int p,int v){
    if(p<l||r<p)return ;
    if(l==r){
        Len[k]=Left[k]=Right[k]=data[k]=v%mod;
        return ;
    }
    if(p<=mid) update(lson,p,v);
    else update(rson,p,v);
    data[k]=(data[k<<1]+data[k<<1|1])%mod;
    data[k]=(data[k]+(Right[k<<1]*Left[k<<1|1])%mod)%mod;
    Left[k]=((Len[k<<1]*Left[k<<1|1])%mod+Left[k<<1])%mod;
    Right[k]=((Len[k<<1|1]*Right[k<<1])%mod+Right[k<<1|1])%mod;
    Len[k]=(Len[k<<1]*Len[k<<1|1])%mod;
}

int main()
{
    int n,q;
    while(~scanf("%d%d",&n,&q)){
        int siz=min(n*8,maxn*4);
        fill(data,data+siz,0);
        fill(Left,Left+siz,0);
        fill(Right,Right+siz,0);
        for(int i=0;i<q;i++){
            int p,v;
            scanf("%d%d",&p,&v);
            update(1,1,n,p,v);
            printf("%d\n",data[1]%mod);
        }
    }
    return 0;
}














放上我SB的map。



#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <map>
#define mid (l+r>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
using namespace std;
const int mod=10007;
const int maxn=1e5+7;
int data[maxn*4];
int Len[maxn*4];
map<int,int > Left[maxn*4],Right[maxn*4];
map<int,int>::iterator it,ip;


void update(int k,int l,int r,int p,int v){//printf("k==%d l==%d r==%d\n",k,l,r);
    if(p<l||r<p)return ;
    if(l==r){
        data[k]=v%mod;
        Left[k].clear();
        Right[k].clear();
        Left[k][(v%mod)]=1;
        Right[k][(v%mod)]=1;
        Len[k]=v%mod;//printf("data[%d]==%d \n",k,data[k]);
        return ;
    }
    if(p<=mid) update(lson,p,v);
    else update(rson,p,v);
    data[k]=(data[k<<1]+data[k<<1|1])%mod;
    for(it=Right[k<<1].begin();it!=Right[k<<1].end();it++){
        for(ip=Left[k<<1|1].begin();ip!=Left[k<<1|1].end();ip++){
            int t1=it->first%mod,t2=it->second%mod,t3=ip->first%mod,t4=ip->second%mod;
            //printf("k== %d t1=%d t2=%d t3=%d t4=%d\n",k,t1,t2,t3,t4);
            int t5=((((t1*t3)%mod)*t2)%mod)*t4%mod;
            data[k]=(data[k]+t5)%mod;
        }
    } //printf("haha\n");
    Left[k].clear();
    for(it=Left[k<<1|1].begin();it!=Left[k<<1|1].end();it++){
        int t1=it->first%mod,t2=it->second%mod;
        Left[k][(t1*Len[k<<1])%mod]=(Left[k][(t1*Len[k<<1])%mod]+t2)%mod;
    }
    for(it=Left[k<<1].begin();it!=Left[k<<1].end();it++)
    Left[k][(it->first)%mod]=(Left[k][(it->first)%mod]+it->second)%mod;//printf("haha2\n");
    ///
    Right[k].clear();//printf("%d %d\n",Right[k<<1].size(),Right[k<<1|1].size());
    for(it=Right[k<<1].begin();it!=Right[k<<1].end();it++){
        int t1=it->first%mod,t2=it->second%mod;//printf("k<<1==%d %d %d \n",k<<1,t1,t2);
        Right[k][(t1*Len[k<<1|1])%mod]=(Right[k][(t1*Len[k<<1|1])%mod]+t2)%mod;
        //Right[k].push_back((Right[k<<1][i]*Right[k<<1|1][0])%mod);//printf("Right[k]==%d*%d \n",Right[k<<1][i],Right[k<<1|1][0]);
    }
    for(it=Right[k<<1|1].begin();it!=Right[k<<1|1].end();it++)
    Right[k][it->first%mod]=(Right[k][it->first%mod]+it->second%mod)%mod;//printf("haha3\n");
    Len[k]=(Len[k<<1]*Len[k<<1|1])%mod; //printf("data[%d]==%d Len %d %d %d\n",k,data[k],Len[k],Len[k<<1],Len[k<<1|1]);
}

void debug(int k,int l,int r){
    printf("debug k==%d data=%d Len=%d Left=%d Right=%d\n",k,data[k],Len[k],Left[k].size(),Right[k].size());
    for(it=Left[k].begin();it!=Left[k].end();it++)printf("Left  k==%d %d %d\n",k,it->first,it->second);
    for(it=Right[k].begin();it!=Right[k].end();it++)printf("Right  k==%d %d %d\n",k,it->first,it->second);
    if(l==r)return ;
    debug(lson);
    debug(rson);
}

int main()
{
    int n,q;
    while(~scanf("%d%d",&n,&q)){
        int siz=min(n*8,maxn*4);
        fill(data,data+siz,0);
        for(int i=0;i<siz;i++){
            Left[i].clear();//Left[i][0]=1;
            Right[i].clear();//Right[i][0]=1;
        }//debug(1,1,n);
        for(int i=0;i<q;i++){
            int p,v;
            scanf("%d%d",&p,&v);
            update(1,1,n,p,v);
            //printf("-----------\n");debug(1,1,n);printf("--------------\n");
            printf("%d\n",data[1]%mod);
        }
    }
    return 0;
}













  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值