CF 256E Lucky Arrays(线段树+DP)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

题目:给出一个序列,初始为0。
其中将每个数调整成1,2,3中的一个,但是有一些要求(ai,ai+1)必须是合法的,矩阵给出
每一个询问,其中有一位的数字是确定的
维护一个线段树,每个节点有一个矩阵a[i][j]表示这个区间的第一个数是i,最后一个是j的数目有多少。
那么初始化的时候,对于叶子,便是a[i][j]=(i==j?1:0)3种情况都有可能
然后向上更新,则需要枚举父亲的两端,然后枚举子节点的另外两端,判断两个内侧相邻是否合法即可。
那么对于每一次查询,则去更新叶子结点
如果该位要求是0,则说明无要求,和初始化一样
否则则将指定的a[i][i]=1。  
结果的话便是根结点的值的和
#include<iostream>  
#include<cstdio>  
#include<map>  
#include<cstring>  
#include<cmath>  
#include<vector>  
#include<stack>
#include<algorithm>  
#include<set>  
#include<string>  
#include<queue>  
#define inf 1600005  
#define M 40  
#define N 80000
#define maxn 2000005  
#define eps 1e-7
#define zero(a) fabs(a)<eps  
#define Min(a,b) ((a)<(b)?(a):(b))  
#define Max(a,b) ((a)>(b)?(a):(b))  
#define pb(a) push_back(a)  
#define mp(a,b) make_pair(a,b)  
#define mem(a,b) memset(a,b,sizeof(a))  
#define LL long long  
#define MOD 777777777
#define lson step<<1
#define rson step<<1|1
#define sqr(a) ((a)*(a))  
#define Key_value ch[ch[root][1]][0]  
#define test puts("OK");
#define pi acos(-1.0)
#define lowbit(x) ((x)&(-(x)))
#pragma comment(linker, "/STACK:1024000000,1024000000")  
#define vi vector<int> 
using namespace std;
int ok[3][3],n,m;
struct Seg_Tree{
    int left,right;
    LL a[3][3];
}L[N*4];
void Push_Up(int step){
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++){
            L[step].a[i][j]=0;
            for(int k=0;k<3;k++)
                for(int r=0;r<3;r++){
                    if(!ok[k][r]) continue;
                    L[step].a[i][j]=(L[step].a[i][j]+(LL)L[lson].a[i][k]*L[rson].a[r][j])%MOD;
                }
        }
}
void Bulid(int step,int l,int r){
    L[step].left=l;
    L[step].right=r;
    if(l==r){
        mem(L[step].a,0);
        for(int i=0;i<3;i++)
            L[step].a[i][i]=1;
        return ;
    }
    int m=(l+r)>>1;
    Bulid(lson,l,m);
    Bulid(rson,m+1,r);
    Push_Up(step);
}
void Update(int step,int pos,int num){
    if(L[step].left==pos&&pos==L[step].right){
        mem(L[step].a,0);
        if(num==-1){
            for(int i=0;i<3;i++)
                L[step].a[i][i]=1;
        }
        else L[step].a[num][num]=1;
        return ;
    }
    int m=(L[step].left+L[step].right)/2;
    if(pos<=m) Update(lson,pos,num);
    else Update(rson,pos,num);
    Push_Up(step);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            scanf("%d",&ok[i][j]);
    Bulid(1,1,n);
    while(m--){
        int pos,num;
        scanf("%d%d",&pos,&num);
        Update(1,pos,num-1);
        LL ans=0;
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                ans=(ans+L[1].a[i][j])%MOD;
        printf("%I64d\n",ans);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值