hdu 5068(线段树+矩阵乘法)

矩阵乘法来进行所有路径的运算, 线段树来查询修改。 关键还是矩阵乘法的结合律。

Harry And Math Teacher

Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 326    Accepted Submission(s): 89

Problem Description

As we all know, Harry Porter learns magic at Hogwarts School. However, learning magical knowledge alone is insufficient to become a great magician. Sometimes, Harry also has to gain knowledge from other certain subjects, such as language, mathematics, English, and even algorithm. 
In Hogwarts, there is a tall castle in which all teachers live. The castle is rather special. In every floor there are two doors, behind each of them there existing two stairs to the next floor’s two doors. And if you are at the i-th floor’s j-th door , then you can just go to the next floor from this door. However, something even more interesting (or we can say "magic") can happen to the stairs: sometimes they break into pieces (making it impossible to go to the next floor), and sometimes the fragments can joint together and become the whole stair again. Now suppose Harry is in the a-th floor (you know, Harry is the hero, so he lives in the teachers’ building somehow), and his math teacher b-th floor. Sometimes the math teacher will call Harry to his room. Facing these magic stairs, Harry gets puzzled how he can go to see the math teacher. Can you help Harry figure out how many ways exactly he can choose without going backwards? You can assume that the change of the stairs will not happen when Harry is on his way. Harry can begin at any doors in floor a and he can end at any doors in floor b. And as Harry want to arrive as soon as possible, so he can not go back to the past. And at the beginning all the stairs are intact. And the answer may be too large, you should output the answer mod 1000000007.

Input

They are sever test cases, you should process to the end of file.
For each test case, there are two integers n and m(2≤n≤50000,1≤m≤50000) in the first line, indicate the number of the castle’s layers and the number of queries. And the following m lines, each line contains three or four integers. If the first integer op equals 0, there are two integers a and b (1≤a<b≤n) follow, indicate the position of Harry and math teacher. Otherwise, there are three integers x,y,z(1≤x<n,1≤y,z≤2)follow, it means that the stair between the xthfloor’s yth door and the (x+1)th floor’s z-th door changes its state(if it is intact, then it breaks else it joints).

Output

For each query, if op equals 0, you should output one line that contains an integer indicates the number of ways from ath floor to the bth floor.

Sample Input

3 1
0 1 3
3 2
1 2 1 1
0 1 3

Sample Output

8
6

Source

BestCoder Round #14

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define MOD 1000000007
#define N 50050

struct node
{
    __int64 g[2][2];
};
int n,m;
int l[4*N],r[4*N];
node num[4*N];

void up(int s)
{
    num[s].g[0][0]=0;num[s].g[0][1]=0;
    num[s].g[1][0]=0;num[s].g[1][1]=0;
    for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
            for(int k=0;k<2;k++)
                num[s].g[i][j] = (num[s].g[i][j]+num[2*s].g[i][k]*num[2*s+1].g[k][j])%MOD;
}

node mul(node x,node y)
{
    node s;
    s.g[0][0]=0; s.g[0][1]=0;
    s.g[1][0]=0; s.g[1][1]=0;
    for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
            for(int k=0;k<2;k++)
                s.g[i][j]=( s.g[i][j]+x.g[i][k]*y.g[k][j])%MOD;
    return s;
}

void build(int tl,int tr,int s)
{
    l[s]=tl;
    r[s]=tr;
    if(tl==tr)
    {
        num[s].g[0][0]=1; num[s].g[0][1]=1;
        num[s].g[1][0]=1; num[s].g[1][1]=1;
        return ;
    }
    int mid = (tl+tr)/2;
    build(tl,mid,2*s);
    build(mid+1,tr,2*s+1);
    up(s);
}

void update(int x,int y,int z,int s)
{
    if(l[s]==x&&r[s]==x)
    {
        int tx,ty;
        if(y==1&&z==1) tx=0,ty=0;
        if(y==1&&z==2) tx=0,ty=1;
        if(y==2&&z==1) tx=1,ty=0;
        if(y==2&&z==2) tx=1,ty=1;
        if(num[s].g[tx][ty]==0)
        {
            num[s].g[tx][ty]=1;
        }
        else num[s].g[tx][ty]=0;
        return ;
    }
    int mid= (l[s]+r[s])/2;
    if(x<=mid) update(x,y,z,2*s);
    else update(x,y,z,2*s+1);
    up(s);
}

node ask(int a,int b,int s)
{
    if(l[s]==a&&r[s]==b)
    {
        return num[s];//这里查询的不对
    }
    int mid=(l[s]+r[s])/2;
    if(b<=mid) return ask(a,b,2*s);
    else if(a>mid) return ask(a,b,2*s+1);
    else
    {
        return mul(ask(a,mid,2*s),ask(mid+1,b,2*s+1));
    }
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        build(1,n-1,1);
        for(int i=0;i<m;i++)
        {
            int a,b,c,d;
            scanf("%d%d%d",&a,&b,&c);
            if(a==0)
            {
                node tmp=ask(b,c-1,1);
                printf("%I64d\n", (tmp.g[0][0]+tmp.g[0][1]+tmp.g[1][0]+tmp.g[1][1])%MOD );
            }
            else
            {
                scanf("%d",&d);
                update(b,c,d,1);
            }
        }
    }
    return 0;
}
时间: 2024-10-18 17:39:30

hdu 5068(线段树+矩阵乘法)的相关文章

HDU 5068 Harry And Math Teacher 线段树+矩阵乘法

题意: 一栋楼有n层,每一层有2个门,每层的两个门和下一层之间的两个门之间各有一条路(共4条). 有两种操作: 0 x y : 输出第x层到第y层的路径数量. 1 x y z : 改变第x层 的 y门 到第x+1层的 z门的通断情况. 思路: 门之间的路径数可以用矩阵来表示,经过的中间层可以用矩阵乘积表示. 所以用线段树维护矩阵乘积即可. 代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring>

zoj 3772 Calculate the Function(线段树+矩阵乘法)

Calculate the Function Time Limit: 2 Seconds      Memory Limit: 65536 KB You are given a list of numbers A1 A2 .. AN and M queries. For the i-th query: The query has two parameters Li and Ri. The query will define a function Fi(x) on the domain [Li,

hdu 5068 线段树加+dp

这题说的是 有n 层每层 有两个门 每个门 可以到达上一层的两个门,然后求从a 层到达b 层的方案总数, 不能后退, 在同一层中不能从第一个门到达另一层 我们只要我们可以对于每个 区间内 有dp[o][2][2] , 表示 在这个区间中 从区间起始到达区间末尾 的两个门分别设 a1,a2, b1,b2, dp[o][0][0],和dp[o][0][1],表示从从a1到b1 和 a2 到 b1 的方案总数 然后同理dp[o][1][0]dp[o][1][1], 得到转移 通过线段树去优化他 得到转

[tsA1490][2013中国国家集训队第二次作业]osu![概率dp+线段树+矩阵乘法]

这样的题解只能舔题解了,,,qaq 清橙资料里有.. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cmath> 6 #include <ctime> 7 #include <algorithm> 8 9 using namespace std; 10 11 struct Mat

ZOJ 3772 Calculate the Function 线段树+矩阵

Calculate the FunctionTime Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu Submit Status Appoint description:  System Crawler  (2014-04-09) Description You are given a list of numbers A1A2 .. AN and M queries. For the i-th query

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

hdu 4893 线段树 --- 也是两个变 类似双标记

http://acm.hdu.edu.cn/showproblem.php?pid=4893 开始的时候,我按双标记,WA了一下午,搞不定,我是用的两个标记add--表示当前结点中有值发生变化,flag,斐波那契的懒惰标记,但是估计是我自己处理的有问题,一直不对 参考了别人的代码,写法还是很不错的,Add变量维护的是,完全变成Fibonacci的时候的和,---回头我再重新写一遍 #include <cstdio> #include <cstring> #include <a

HDU 4902 线段树||暴力

给定一个序列,两种操作 1:把一段变成x. 2:把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 线段树解法:用lazy标记下即可,优化方法还是很巧妙的, Accepted 4902 515MS 3308K 1941 B C++ #include "stdio.h" #include "string.h" struct node { int l,r,x;// 在叶子节点代表值,树节点代表成端更新的lazy操作. }data[400010]