codeforces CF718C Sasha and Array 线段树维护矩阵

$ \Rightarrow $ 戳我进CF原题

C. Underground Lab


time limit per test: 1 second
memory limit per test: 256 megabytes
input: standard input
output: standard output



 

The evil Bumbershoot corporation produces clones for gruesome experiments in a vast underground lab.
On one occasion, the corp cloned a boy Andryusha who was smarter than his comrades.
Immediately Andryusha understood that something fishy was going on there.
He rallied fellow clones to go on a feud against the evil corp, and they set out to find an exit from the lab.
The corp had to reduce to destroy the lab complex.
 
The lab can be pictured as a connected graph with $ n $ vertices and $ m $ edges.
$ k $ clones of Andryusha start looking for an exit in some of the vertices.
Each clone can traverse any edge once per second. Any number of clones are allowed to be at any vertex simultaneously.
Each clone is allowed to stop looking at any time moment, but he must look at his starting vertex at least.
The exit can be located at any vertex of the lab, hence each vertex must be visited by at least one clone.
 
Each clone can visit at most $ \lceil \frac{2n}{k} \rceil $ vertices before the lab explodes.
 
Your task is to choose starting vertices and searching routes for the clones. Each route can have at most $ \lceil \frac{2n}{k} \rceil $ vertices.
 

Input

The first line contains three integers $ n, m,$ and $ k (1?≤?n?≤?2·10^5, n?-?1?≤?m?≤?2·10^5, 1?≤?k?≤?n) $
— the number of vertices and edges in the lab, and the number of clones.
 
Each of the next $ m $ lines contains two integers $ x_i $ and $ y_i (1?≤?x_i,?y_i?≤?n) $
— indices of vertices connected by the respective edge. The graph is allowed to have self-loops and multiple edges.
 
The graph is guaranteed to be connected.
 

Output

You should print $ k $ lines.
$ i $-th of these lines must start with an integer $ c_i (1 \le c_i \le \lceil \frac{2n}{k} \rceil ) $ — the number of vertices visited by $ i $-th clone,
followed by $ c_i $ integers — indices of vertices visited by this clone in the order of visiting.
You have to print each vertex every time it is visited, regardless if it was visited earlier or not.
 
It is guaranteed that a valid answer exists.
 

Examples

input1

 3 2 1
 2 1
 3 1

output1

 3 2 1 3

input2

 5 4 2
 1 2
 1 3
 1 4
 1 5

output2

 3 2 1 3
 3 4 1 5

 

Note

In the first sample case there is only one clone who may visit vertices in order $ (2, 1, 3) $ ,
which fits the constraint of $ 6 $ vertices per clone.
 
In the second sample case the two clones can visited vertices in order $ (2, 1, 3) $ and $ (4, 1, 5) $ ,
which fits the constraint of $ 5 $ vertices per clone.
 

题目大意

  • 维护一个序列,支持两种操作:
  1. 区间 $ [l,r] $ 的权值 $ +x $
  2. 询问区间 $ [l,r] $ 的函数和,即 $ \sum fib(x) $ 这里的函数即斐波那契函数
  • 数据范围: $ 1 \le n,q \le 10^5 $
     

思路

  • 一般求斐波那契函数的方法可以考虑矩阵乘法,这里也是这样的。
  • 我们不用线段树维护权值,我们用线段树维护区间矩阵和。
  • 有一个矩阵乘法的性质:$ A \times B + A \times C = A \times (B+C) $
  • 在求斐波那契数列中,是 $ A \times F $ ,$ A $ 是变换矩阵, $ F $ 是列矩阵
  • 那么我们用线段树的 $ lazy $ 标记维护 $ A $ 矩阵,然后用 $ sum $ 维护 $ F $ 矩阵
  • 之后在线段树上,就变成了区间更新乘以 $ x $
     

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define int long long
#define N 100005
#define Mod 1000000007
inline int read() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
struct Matrix{
    int x[3][3];
    inline void clear(){
        for(int i=1;i<=2;++i)
            for(int j=1;j<=2;++j)
                x[i][j]=0;
    }
    inline void init(){
        for(int i=1;i<=2;++i)
            x[i][i]=1;
    }
    inline bool empty(){
        if(x[1][1]!=1||x[1][2]!=0) return 0;
        if(x[1][2]!=0||x[2][2]!=1) return 0;
        return 1;
    }
    inline void print(){
        for(int i=1;i<=2;i++){
            for(int j=1;j<=2;j++)
                printf("%lld ",x[i][j]);
            cout<<endl;
        }
    }
    inline Matrix operator * (const Matrix &y) const{
        Matrix c; c.clear();
        for(int i=1;i<=2;++i)
            for(int j=1;j<=2;++j)
                for(int k=1;k<=2;++k)
                    c.x[i][j]=(c.x[i][j]+x[i][k]*y.x[k][j]%Mod)%Mod;
        return c;
    }
    inline Matrix operator + (const Matrix &y) const{
        Matrix c; c.clear();
        for(int i=1;i<=2;++i)
            for(int j=1;j<=2;++j)
                c.x[i][j]=(x[i][j]+y.x[i][j])%Mod;
        return c;
    }
}st,ss,sum[N<<2],lzy[N<<2];
Matrix qpow(Matrix x,int k){
    Matrix res; res.clear(); res.init();
    while(k>0){
        if(k&1) res=res*x;
        x=x*x;
        k>>=1;
    }
    return res;
}
int n,m;
void build(int o,int l,int r){
    lzy[o].init();
    if(l==r){
        sum[o]=ss*qpow(st,read()-1);
        return;
    }
    int mid=l+r>>1;
    build(o<<1,l,mid); build(o<<1|1,mid+1,r);
    sum[o]=sum[o<<1]+sum[o<<1|1];
}
inline void pushdown(int o){
    sum[o<<1]=sum[o<<1]*lzy[o];
    sum[o<<1|1]=sum[o<<1|1]*lzy[o];
    lzy[o<<1]=lzy[o<<1]*lzy[o];
    lzy[o<<1|1]=lzy[o<<1|1]*lzy[o];
    lzy[o].clear();
    lzy[o].init();
}
void updata(int o,int l,int r,int L,int R,Matrix k){
    if(L<=l&&r<=R){
        sum[o]=sum[o]*k;
        lzy[o]=lzy[o]*k;
        return;
    }
    if(!lzy[o].empty()) pushdown(o);
    int mid=l+r>>1;
    if(L>mid) updata(o<<1|1,mid+1,r,L,R,k);
    else if(R<=mid) updata(o<<1,l,mid,L,R,k);
    else {
        updata(o<<1,l,mid,L,R,k);
        updata(o<<1|1,mid+1,r,L,R,k);
    }
    sum[o]=sum[o<<1]+sum[o<<1|1];
}
Matrix query(int o,int l,int r,int L,int R){
    if(L<=l&&r<=R) return sum[o];
    if(!lzy[o].empty()) pushdown(o);
    int mid=l+r>>1;
    if(L>mid) return query(o<<1|1,mid+1,r,L,R);
    else if(R<=mid) return query(o<<1,l,mid,L,R);
    else return query(o<<1,l,mid,L,R)+query(o<<1|1,mid+1,r,L,R);
    sum[o]=sum[o<<1]+sum[o<<1|1];
}
signed main(){
    st.x[1][1]=0; st.x[1][2]=1;
    st.x[2][1]=1; st.x[2][2]=1;

    ss.x[1][1]=0; ss.x[1][2]=1;
    ss.x[1][2]=0; ss.x[2][2]=1;

    n=read(); m=read();
    build(1,1,n);
    while(m--){
        int opt=read(),L=read(),R=read();
        if(opt==1){
            updata(1,1,n,L,R,qpow(st,read()));
        }
        else{
            Matrix ans=query(1,1,n,L,R);
            printf("%lld\n",(ans.x[1][2]+ans.x[2][2])%Mod);
        }
    }
    return 0;
}
/*
#         42721582
When      2018-09-10 05:12:59
Who       PotremZ
Problem   C - Sasha and Array
Lang      GNU C++11
Verdict   Accepted
Time      3541 ms
Memory    56400 KB
*/

原文地址:https://www.cnblogs.com/PotremZ/p/9657481.html

时间: 2024-07-30 23:10:08

codeforces CF718C Sasha and Array 线段树维护矩阵的相关文章

CF719E. Sasha and Array [线段树维护矩阵]

CF719E. Sasha and Array 题意: 对长度为 n 的数列进行 m 次操作, 操作为: a[l..r] 每一项都加一个常数 C, 其中 0 ≤ C ≤ 10^9 求 F[a[l]]+F[a[l+1]]+...F[a[r]] mod 1e9+7 的余数 矩阵快速幂求斐波那契 矩阵满足乘法分配律和结合律! 所以可以每个节点维护矩阵/矩阵和,区间加相当于区间乘矩阵 注意:不要把快速幂写在里面,复杂度平添一个log.把\(B^C\)算出来之后传进去就好了 #include <iostr

CF718C Sasha and Array(线段树维护矩阵)

题解 (不会矩阵加速的先去学矩阵加速) 反正我想不到线段树维护矩阵.我太菜了. 我们在线段树上维护一个区间的斐波那契的列矩阵的和. 然后询问时提取每个符合题意列矩阵的答案项(不是列矩阵存了两项吗,一个是当前项,一个是用来递推的) 因为矩阵乘有结合律所以区间加这个操作就直接区间乘变换矩阵的x次方就行. 然后记得开long long 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include&

Subsequence Count 2017ccpc网络赛 1006 dp+线段树维护矩阵

Problem Description Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries on the string.There are two types of queries:1. Flipping the bits (i.e., changing all 1 to 0 and 0 to 1) between l and r (inclusive).2. Counting the

Codeforces GYM 100114 D. Selection 线段树维护DP

D. Selection Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Description When selecting files in an application dialog, Vasya noted that he can get the same selection in different ways. A simple mouse click selects a sing

HDU 6155 Subsequence Count 线段树维护矩阵

Subsequence Count Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others) Problem Description Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries on the string. There are two types of querie

codeforces Good bye 2016 E 线段树维护dp区间合并

题目大意:给你一个字符串,范围为'0'~'9',定义一个ugly的串,即串中的子串不能有2016,但是一定要有2017,问,最少删除多少个字符,使得串中符合ugly串? 思路:定义dp(i, j),其中i=5,j=5,因为只需要删除2016当中其中一个即可,所以一共所需要删除的字符和需要的字符为20176,因此i和j只要5就够了. 然后转移就是dp(i,i) = 0, 如果说区间大小为1的话,那么如果是2017中的一个,那么就是dp(pos, pos+1) = 0, dp(pos,pos) =

[动态dp]线段树维护转移矩阵

背景:czy上课讲了新知识,从未见到过,总结一下. 所谓动态dp,是在动态规划的基础上,需要维护一些修改操作的算法. 这类题目分为如下三个步骤:(都是对于常系数齐次递推问题) 1先不考虑修改,不考虑区间,直接列出整个区间的dp方程.这个是基础,动态dp无论如何还是dp(这一步是一般是重点) 2.列出转移矩阵.由于有很多修改操作,我们将数据集中在一起处理,还可以利用矩阵结合律,并且区间比较好提取,(找一段矩阵就好了),修改也方便. 3.线段树维护矩阵.对于修改,我们就是在矩阵上进行修改,对于不同的

Codeforces 482B Interesting Array(线段树)

题目链接:Codeforces 482B Interesting Array 题目大意:给定一个长度为N的数组,现在有M个限制,每个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是 否有满足的数列. 解题思路:线段树维护,每条限制等于是对l~r之间的数或上q(取且的性质,相应二进制位一定为1),那么处理完所有的 限制,在进行查询,查询对应每个l~r之间的数取且是否还等于q.所以用线段树维护取且和,修改为或操作. #include <cstdio> #include <c

CodeForces 343D 线段树维护dfs序

给定一棵树,初始时树为空 操作1,往某个结点注水,那么该结点的子树都注满了水 操作2,将某个结点的水放空,那么该结点的父亲的水也就放空了 操作3,询问某个点是否有水 我们将树进行dfs, 生成in[u], 访问结点u的时间戳,out[u],离开结点u的时间戳 每个结点的in值对应在线段树中的区间的一点 那么对于操作1, 只要将区间[in[u],out[u]] 的值都改为1, 但是如果区间[in[u],out[u]] 原先存在为0的点,那么父区间肯定是空的,这个操作不能 改变父区间的状态,所以需要