【解题报告】ZJNU 个人赛五(2021)

B

题意

  • N N N 个点,第 i i i 个点目标颜色为 a i a_i ai
    Q Q Q 个询问,第 i i i 个表示只涂区间 [ L i , R i ] [L_i,R_i] [Li,Ri] 的最少次数
  • 刷一次颜色 c c c 的要求:刷满一个连续的区间,且区间区间中所有已涂颜色都必须小于等于 c c c,然后该区间的所有颜色变成 c c c
  • 1 ≤ N , Q ≤ 2 e 5 1\le N,Q\le 2e5 1N,Q2e5

思路

  • 之前的某道题目是相当于询问一次 [ 1 , N ] [1,N] [1,N] 的答案,是使用单调栈去做的,但是这次有很多个询问,肯定不能全部暴力去跑。
  • 场上想到了莫队,但是貌似挺麻烦的…
    看一下用线段树的解法:
  • 首先,我们原题目为什么用单调栈去做呢?
    对于两个位置 p 1 , p 2 p_1,p_2 p1,p2 a p 1 = a p 2 a_{p_1}=a_{p_2} ap1=ap2 p 1 < p 2 p_1<p_2 p1<p2
    如果 ∀ p 3 \forall p_3 p3 满足 p 1 < p 3 < p 2 p_1<p_3<p_2 p1<p3<p2,且 a p 3 > a p 1 = a p 2 a_{p_3}>a_{p_1}=a_{p_2} ap3>ap1=ap2
    也就是说这两个位置我们只用一次涂就可以了
  • 转换一下,也就是我们对于某个询问区间 [ L , R ] [L,R] [L,R]
    我们需要知道有多少对 p 1 , p 2 p_1,p_2 p1,p2,在这个区间中且满足上述的要求,假设有 t m p tmp tmp
    那么答案为多少呢?为 ( R − L + 1 ) − t m p (R-L+1)-tmp (RL+1)tmp
    为什么呢?可以理解为如果找到了一对,因为他们可以通过一次涂色解决,相当于把这两个点给合并了,即点的个数 − 1 -1 1
    最后就是求这个区间内还剩下多少个无法合并的点,就是区间长度 减去 合并次数
  • 那么我们怎么去求这个 t m p tmp tmp 呢?
    我们可以离线做,把询问对给排序,按照右端点升序
    然后像一般的单调栈一样,我们按顺序一个一个把点加进来,然后把栈顶大于目前点的颜色的点给 p o p pop pop
  • 如果栈顶颜色等于目前点的颜色,那么我们就是找到了这一对点
    也就是说,如果区间的左端点小于等于栈顶元素的位置,那么这个区间囊括了这一对点
    转化一下,我们每次把这个栈顶元素的位置 p p p 获得, v a l [ p ] + + val[p]++ val[p]++
    最后询问,只要查询 [ L , R ] [L,R] [L,R] 之内 v a l [ i ] val[i] val[i] 的和,就是我们的 t m p tmp tmp
    用树状数组会快一点

代码

  • 时间复杂度: O ( Q log ⁡ Q + N log ⁡ N ) O(Q\log Q+N\log N) O(QlogQ+NlogN)
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long ll;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}

const int MAX = 2e5+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const double EPS = 1e-5;

int lowbit(int x){return x&(-x);}
struct SZSZ{
    int a[MAX];
    void init(){for(int i=0;i<MAX;++i)a[i]=0;}
    void update(int x,int k){while(x<MAX){a[x]+=k;x+=lowbit(x);}}
    int query(int x){int r=0;while(x){r+=a[x];x-=lowbit(x);}return r;}
    int query(int l,int r){return query(r) - query(l-1);}
}tree;

int aa[MAX];
struct node{
    int l,r,L,id;
    bool operator <(const node &ND)const{		// 询问排序
        if(r != ND.r)return r < ND.r;
        return l < ND.l;
    }
}que[MAX];
int ans[MAX];
int main()
{
    IOS;
    int n,q;
    cin >> n >> q;
    for(int i = 1;i <= n;++i)cin >> aa[i];
    for(int i = 1;i <= q;++i){
        cin >> que[i].l >> que[i].r;
        que[i].L = que[i].r - que[i].l+1;
        que[i].id = i;
    }
    sort(que+1,que+1+q);
    stack<int>S;
    int pos = 1;
    for(int i = 1;i <= n;++i){		// 单调栈
        while(!S.empty() && aa[S.top()] > aa[i])S.pop();
        if(!S.empty() && aa[S.top()] == aa[i]){		// 找到了一对合法点
            tree.update(S.top(),1);
            S.pop();
        }
        S.push(i);
        while(pos <= q && que[pos].r == i){		// 答案查询
            ans[que[pos].id] = que[pos].L - tree.query(que[pos].l,que[pos].r);
            pos++;
        }
    }
    for(int i = 1;i <= q;++i){
        cout << ans[i] << endl;
    }
    return 0;
}
/**

*/

C

题意

  • 给定一个 N × N N\times N N×N 的矩阵 S i , j S_{i,j} Si,j
    求有多少个子矩阵 S ′ S^\prime S,满足子矩阵元素 min ⁡ { S ′ } = 100 \min\{S^\prime\}=100 min{S}=100
  • 1 ≤ N ≤ 500 1\le N\le 500 1N500

思路

  • = A =A =A 问题难,就转化为求 ≥ A \ge A A 以及 > A >A >A 的问题
    这里,就是求有多少个子矩阵满足 min ⁡ { S ′ } ≥ 100 \min\{S^\prime\}\ge100 min{S}100 以及 = 100 =100 =100
  • 我们就看第一个问题,若 S i , j ≥ 100 S_{i,j}\ge 100 Si,j100,我们就令 A i , j = 1 A_{i,j}=1 Ai,j=1,否则 A i , j = 0 A_{i,j}=0 Ai,j=0
    然后就转化为了另一个问题:求有多少个全 1 1 1子矩阵
  • 首先数据范围当然不允许我们把每个子矩阵去遍历检查
    我们想一下,如果矩阵左上角为 ( i , j ) (i,j) (i,j),然后有多少个高为 1 1 1 的全一子矩阵?就是获得 max ⁡ { t } \max\{t\} max{t},满足 A i , j ∼ A i , k A_{i,j}\sim A_{i,k} Ai,jAi,k 都是 1 1 1
    然后有多少个高为 2 2 2 的全一子矩阵?就是 min ⁡ { t , p } \min\{t,p\} min{t,p},满足 A i + 1 , j ∼ A i + 1 , p = 1 A_{i+1,j}\sim A_{i+1,p}=1 Ai+1,jAi+1,p=1
    看图:
    在这里插入图片描述
  • 也就是说,我们事先预处理出 y o u [ i ] [ j ] you[i][j] you[i][j] 表示从 A i , j A_{i,j} Ai,j 开始,向右,第一个碰到 0 0 0 的位置是多少
    预处理是可以 O ( N 2 ) O(N^2) O(N2) 的,我偷个懒写了个 O ( N 3 ) O(N^3) O(N3)
    然后答案查询,枚举左上角 O ( N 2 ) O(N^2) O(N2),然后一行一行向下枚举 O ( N ) O(N) O(N),总共 O ( N 3 ) O(N^3) O(N3)

代码

  • 时间复杂度: O ( N 3 ) O(N^3) O(N3)
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long ll;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}

const int MAX = 5e2+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const double EPS = 1e-5;

int shu[MAX][MAX];
int aa[MAX][MAX];
int you[MAX][MAX];

ll solve(int n){
    for(int i = 1;i <= n;++i){
        for(int j = 1;j <= n;++j){
            if(aa[i][j] == 0){
                you[i][j] = 0;
                continue;
            }
            for(int k = j;k <= n+1;++k){	// 注意下如果右边没有0的话,you[i][j]=n+1
                if(aa[i][k] == 0){
                    you[i][j] = k;
                    break;
                }
            }
        }
    }
    ll ans = 0;
    for(int i = 1;i <= n;++i)
    for(int j = 1;j <= n;++j){
        int mn = INF;
        if(aa[i][j] == 0)continue;
        for(int k = i;k <= n;++k){
            mn = min(mn,you[k][j]);
            if(mn >= j){
                ans += (mn - j);
            }else break;
        }
    }
    return ans;
}

int main()
{
    int n;scanf("%d",&n);
    for(int i = 1;i <= n;++i)
    for(int j = 1;j <= n;++j)
        scanf("%d",&shu[i][j]);

    ll ans1,ans2;
    for(int i = 1;i <= n;++i){
        for(int j = 1;j <= n;++j){
            if(shu[i][j] >= 100)aa[i][j] = 1;
            else aa[i][j] = 0;
        }
    }
    ans1 = solve(n);
    for(int i = 1;i <= n;++i){
        for(int j = 1;j <= n;++j){
            if(shu[i][j] > 100)aa[i][j] = 1;
            else aa[i][j] = 0;
        }
    }
    ans2 = solve(n);
//    show(ans1,ans2);
    printf("%lld",ans1-ans2);

    return 0;
}
/**

*/

D

题意

  • N N N 个点,第 i i i 个点的位置为 A i A_i Ai
    如果位置为 12 X 12X 12X,其中 X ∈ N ∗ X\in N^* XN,那么该位置有一个传送门,只能在传送门传送到另一个传送门
    没有点的位置在传送门处
    你一开始在位置 0 0 0,只能使用 K K K 次传送门,且移动只能每秒向负方向移动 1 1 1,传送不花时间
    问你访问过所有点,最后回到原点的最短时间
  • 1 ≤ N ≤ 65536 1\le N\le 65536 1N65536
    1 ≤ K ≤ N 1\le K\le N 1KN

思路

  • 因为每个点一定在某两个相邻传送门的中间,我们按块分,算出每个点的块。我们设 [ 0 , 11 ] [0,11] [0,11] 属于第一个块, [ 12 ( X − 1 ) , 12 X ) [12(X-1),12X) [12(X1),12X) 属于第 X X X 个块
  • 那么,所有的点所在的块都需要移动过,这些 12 12 12 单位时间都是必须的
  • 传送影响的是什么呢?影响的是块与块之间的距离,你到底是传送走还是自己慢慢走,看图:
    在这里插入图片描述
  • 直接排序贪心,块与块之间的最大的那 K K K 个距离我们传送走,其他的我们就自己走
    不过要稍微注意一下,因为我们还要回来原点,特判一下就行

代码

  • 时间复杂度: O ( N log ⁡ N ) O(N\log N) O(NlogN)
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long ll;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}

const int MAX = 1e5+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const double EPS = 1e-5;

int aa[MAX];

int blo[MAX];

int get_zuo(int blo){
    return (blo + 1) * 12;
}
int get_you(int blo){
    return blo * 12;
}
int id;
int tmp[MAX];
int cha[MAX];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i = 1;i <= n;++i)scanf("%d",&aa[i]);
    sort(aa+1,aa+1+n,greater<int>());
    int las = -1;
    int ans = 0;
    for(int i = 1;i <= n;++i){
        blo[i] = aa[i] / 12;
        if(blo[i] != las){		// 获得所有不同的块,存在 tmp[] 里面
            tmp[id++] = blo[i];
            las = blo[i];
            ans += 12;			// 这些块的12是必跑的
        }
    }
    if(tmp[id-1] != 0){		// 如果最后一个块不包含原点,我们新加一个原点块
        tmp[id++] = -1;
//        show("ADD");
    }
    for(int i = 0;i+1 < id;++i){
        cha[i] = get_you(tmp[i]) - get_zuo(tmp[i+1]);		// 距离为左边块的右端点减去右边块的左端点
//        show(get_you(tmp[i]),get_zuo(tmp[i+1]));
    }
    sort(cha,cha+id-1,greater<int>());
    k--;
    for(int i = 0;i+1 < id;++i){
//        show(cha[i]);
        if(k)k--;
        else ans += cha[i];
    }
    printf("%d",ans);
    return 0;
}
/**
1 1
100

1 2
100

1 1
5
*/

F

题意

  • 给定一个有方向的路径,长度为 S S S,每一步为向东南西北其中走一步
    这个路径只有开头和结尾重合。问该路径是顺时针还是逆时针的

思路

  • 看图:
    在这里插入图片描述
  • 我们只要知道其中一条最侧面的线段,其方向决定了该闭合路径是顺时针还是逆时针的

代码

  • 时间复杂度: O ( ∣ S ∣ ) O(|S|) O(S)
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long ll;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}

const int MAX = 3e2+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const double EPS = 1e-5;

int main()
{
    int n;scanf("%d",&n);
    while(n--){
        string ss;int l;cin >> ss;
        l = ss.size();
        int nowx = 0;
        int nowy = 0;
        int zuoy = 0;
        int dir = 0;
        for(int i = 0;i < l;++i){
            if(ss[i] == 'N')nowx--;
            else if(ss[i] == 'S')nowx++;
            else if(ss[i] == 'W')nowy--;
            else if(ss[i] == 'E')nowy++;
            if(nowy == zuoy){
                if(ss[i] == 'N')dir = -1;
                else if(ss[i] == 'S')dir = 1;
            }
            if(nowy < zuoy){
                zuoy = nowy;
            }
        }
        if(dir == -1)puts("CW");
        else puts("CCW");
    }
    return 0;
}

G

题意

  • N N N 个点,一开始每个点值为 0 0 0
    每一步,可以选择一段区间 [ L , R ] [L,R] [L,R],然后把他们的值都变为一个任意的 c c c
    问最少步数,让第 i i i 个点的值为 A i A_i Ai
  • 1 ≤ N ≤ 300 1\le N\le 300 1N300

思路

  • 容易想到是区间 D P DP DP,但是场上对一笔画的点想错了于是只有 60 60 60 分…
  • d p [ i ] [ j ] dp[i][j] dp[i][j] 表示区间 [ i , j ] [i,j] [i,j] 全部满足要求的最少步数
    先枚举区间长度 L L L,再枚举区间左端点,同时获得了区间右端点;再枚举区间端点,很快获得很简单的维护:
    d p [ i ] [ j ] = min ⁡ { d p [ i ] [ k ] + d p [ k + 1 ] [ j ] } dp[i][j]=\min\{dp[i][k]+dp[k+1][j]\} dp[i][j]=min{dp[i][k]+dp[k+1][j]}
    就是一个区间涂完,等于左边一个区间涂完步数+右边区间涂完步数
  • 然后再考虑某一笔横穿整个区间的情况。
    *由于某一笔横穿部分区间的情况在 L L L 较小的情况已经考虑到,因此我们只考虑某一笔横穿某个区间
    也就是满足 A i = A j A_i=A_j Ai=Aj
    此时的转移:
    d p [ i ] [ j ] = min ⁡ { d p [ i + 1 ] [ j ] , d p [ i ] [ j − 1 ] } dp[i][j]=\min\{dp[i+1][j],dp[i][j-1]\} dp[i][j]=min{dp[i+1][j],dp[i][j1]}

代码

  • 时间复杂度: O ( N 3 ) O(N^3) O(N3)
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long ll;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}

const int MAX = 3e2+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const double EPS = 1e-5;

int aa[MAX];
int dp[MAX][MAX];

int main()
{
    int n;scanf("%d",&n);
    for(int i = 1;i <= n;++i)scanf("%d",&aa[i]);
    for(int i = 1;i <= n;++i)
    for(int j = i;j <= n;++j)
        dp[i][j] = INF;

    for(int i = 1;i <= n;++i)dp[i][i] = 1;

    for(int L = 2;L <= n;++L){
        for(int i = 1;i + L - 1 <= n;++i){
            int j = i + L - 1;
            if(aa[i] == aa[j])dp[i][j] = min(dp[i+1][j],dp[i][j-1]);	// 场上写成 dp[i][j]=dp[i+1][j-1]+1,明显是不对的
            for(int k = i;k+1 <= j;++k){
                dp[i][j] = min(dp[i][j],dp[i][k] + dp[k+1][j]);
            }
        }
    }

    printf("%d",dp[1][n]);

    return 0;
}

H

题意

  • N N N 头牛,第 i i i 次加入一头牛,坐标为 ( x i , y i ) (x_i,y_i) (xi,yi)
    问你每次加入后有多少头牛是舒服的
    一头牛是舒服的,当且仅当他上下左右四个相邻位置有三头牛
  • 1 ≤ N ≤ 1 0 5 1\le N\le 10^5 1N105

思路

  • 模拟,加入牛判断它舒不舒服,以及对周围四个方向的影响

代码

  • 时间复杂度: O ( N ) O(N) O(N)
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long ll;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}

const int MAX = 1e3+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const double EPS = 1e-5;

bool aa[MAX][MAX];
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
int shu(int x,int y){		// 坐标(i,j) 相邻四个位置有几头牛
    int num = 0;
    for(int i = 0;i < 4;++i){
        int tx = x + dx[i];
        int ty = y + dy[i];
        if(tx < 0 || ty < 0 || tx > 1000 || ty > 1000)continue;
        if(aa[tx][ty])num++;
    }
    return num;
}
int main()
{
    int ans = 0;
    int n;scanf("%d",&n);
    for(int i = 1;i <= n;++i){
        int x,y;scanf("%d%d",&x,&y);
        aa[x][y] = true;
        for(int j = 0;j < 4;++j){
            int tx = x + dx[j];
            int ty = y + dy[j];
            if(tx < 0 || ty < 0 || tx > 1000 || ty > 1000)continue;
            if(!aa[tx][ty])continue;		// 它不是牛就不用去check了
            int tmp = shu(tx,ty);
            if(tmp == 3)ans++;
            else if(tmp == 4)ans--;
        }
        if(shu(x,y) == 3)ans++;
        printf("%d\n",ans);
    }
    return 0;
}

I

题意

  • N N N 头牛,第 i i i 次加入牛的位置为 ( x i , y i ) (x_i,y_i) (xi,yi)
    问你对于已经加入 1 ∼ i 1\sim i 1i 头牛的情况下,最少需要加多少头牛,才能让每头牛(包括新加入的牛)都不舒服
    一头牛是舒服的,当且仅当他上下左右四个相邻位置有三头牛
    每一次询问是独立的
  • 1 ≤ N ≤ 1 0 5 1\le N\le 10^5 1N105

思路

  • M [ i ] [ j ] = 0 M[i][j]=0 M[i][j]=0 表示位置 ( i , j ) (i,j) (i,j) 什么都没有
    M [ i ] [ j ] = 1 M[i][j]=1 M[i][j]=1 表示该位置放了牛
    M [ i ] [ j ] = 2 M[i][j]=2 M[i][j]=2 表示该位置放了我们假想的牛
  • 对于某头牛,如果该牛舒服的话,那么我们在其周围四格子中的空的格子,放入一头假想的牛
    然是放入新的牛可能导致新的牛边舒服,深搜去解决

代码

  • 时间复杂度: O ( N ) O(N) O(N)
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long ll;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}

const int MAX = 3e2+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const double EPS = 1e-5;

unordered_map<int,unordered_map<int,int> >M;    // 0 : none 1 : cow 2 : fake cow
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};

int get_shu(int x,int y){
    int num = 0;
    for(int i = 0;i < 4;++i){
        int tx = x + dx[i];
        int ty = y + dy[i];
        if(M[tx][ty])num++;
    }
    return num;
}
int ans = 0;
void dfs(int x,int y){
    int num = get_shu(x,y);
    if(num == 3){
        if(M[x][y]){
            for(int i = 0;i < 4;++i){
                int tx = x + dx[i];
                int ty = y + dy[i];
                if(M[tx][ty] == 0){
                    M[tx][ty] = 2;
                    ans++;
                    dfs(tx,ty);
                    break;
                }
            }
        }
    }
    for(int i = 0;i < 4;++i){
        int tx = x + dx[i];
        int ty = y + dy[i];
//        show(tx,ty,get_shu(tx,ty));
        if(get_shu(tx,ty) == 3 && M[tx][ty])dfs(tx,ty);
    }
}
int main()
{
    int n;scanf("%d",&n);
    for(int i = 1;i <= n;++i){
        int x,y;
        scanf("%d%d",&x,&y);
        if(M[x][y] == 2){
            ans--;
            M[x][y] = 1;
        }else{
            M[x][y] = 1;
            dfs(x,y);
        }
//        for(int j = 0;j <= 5;++j){
//            for(int k = 0;k <= 5;++k){
//                cout << M[j][k] << " ";
//            }
//            puts("");
//        }
//        puts("");
        printf("%d\n",ans);
    }
    return 0;
}

K

题意

  • 区间乘的线段树板子

代码

  • 时间复杂度: O ( N log ⁡ N ) O(N\log N) O(NlogN)
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long ll;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}

const int MAX = 1e5+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const double EPS = 1e-5;

#define ls (p<<1)
#define rs (p<<1|1)
#define md ((l+r)>>1)

ll aa[MAX];
ll tree[MAX*4],tmul[MAX*4];
void push_up(int p){
    tree[p] = tree[ls] + tree[rs];
}
void build(int p,int l,int r){
    tmul[p] = 1;
    if(l == r){
        tree[p] = aa[l];
        return;
    }
    build(ls,l,md);
    build(rs,md+1,r);
    push_up(p);
}
void add(int p,int l,int r,ll mul){
    tree[p] = tree[p] * mul;
    tmul[p] *= mul;
}
void push_down(int p,int l,int r){
    add(ls,l,md,tmul[p]);
    add(rs,md+1,r,tmul[p]);
    tmul[p] = 1;
}
void updateMul(int p,int l,int r,int ux,int uy,int k){
    if(ux <= l && uy >= r){
        add(p,l,r,k);
        return;
    }
    push_down(p,l,r);
    if(ux <= md)updateMul(ls,l,md,ux,uy,k);
    if(uy >  md)updateMul(rs,md+1,r,ux,uy,k);
    push_up(p);
}
ll query(int p,int l,int r,int qx,int qy){
    ll res = 0;
    if(qx <= l && r <= qy)return tree[p];
    push_down(p,l,r);
    if(qx <= md)res += query(ls,l,md,qx,qy);
    if(qy >  md)res += query(rs,md+1,r,qx,qy);
    return res;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;++i)scanf("%lld",&aa[i]);
    build(1,1,n);
    for(int i = 1;i <= m;++i){
        int op,ta,tb;
        scanf("%d%d%d",&op,&ta,&tb);
        if(op == 1){
            updateMul(1,1,n,ta,tb,-1);
        }else{
            printf("%lld\n",query(1,1,n,ta,tb));
        }
    }
    return 0;
}

L

题意

  • 模拟

思路

  • 看代码

代码

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long ll;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}

const int MAX = 1e5+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const double EPS = 1e-5;

map<string,int>M;
map<string,int>year;
int ori = 2000;
int zodiac[MAX];
void init(){
    M["Ox"]=0;
    M["Tiger"]=1;
    M["Rabbit"]=2;
    M["Dragon"]=3;
    M["Snake"]=4;
    M["Horse"]=5;
    M["Goat"]=6;
    M["Monkey"]=7;
    M["Rooster"]=8;
    M["Dog"]=9;
    M["Pig"]=10;
    M["Rat"]=11;
    zodiac[ori] = 0;
    year["Bessie"]=ori;
}

int cha(int nian,int rela,int zod){
    int now = zodiac[nian];
    int res = nian;
    if(rela == 1){
        now = (now + 1) % 12;
        res++;
        while(now != zod){
            now = (now + 1) % 12;
            res++;
        }
    }else{
        now = (now + 11) % 12;
        res--;
        while(now != zod){
            now = (now + 11) % 12;
            res --;
        }
    }
    zodiac[res] = zod;
    return res - nian;
}
int main()
{
    init();
    int n;cin >> n;
    for(int i = 1;i <= n;++i){
        string name1,name2,time,zod,tt;
        cin >> name1 >> tt >> tt >> time >> zod >> tt >> tt >> name2;
        int rela = (time[0] == 'p') ? (-1) : (1);
        int tmp = cha(year[name2],rela,M[zod]);
        year[name1] = year[name2] + tmp;
//        show(name1,year[name1]);
    }
    cout << abs(year["Bessie"]-year["Elsie"]);
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值