[NOIP2018模拟赛] 小P的国际象棋

题目描述

小P迷上了一种新国际象棋,这种国际象棋的棋盘是两个序列,一个序列是自己的部分,另一个序列是对手的。在序列中,每一格都是一个士兵,士兵们的初始战斗力不同。 在新国际象棋种获胜方式是这样的:有q次对决,每次对决双方序列的两个区间,如果小P在这个区间内的士气和大于对手在这个区间内的士气和,那么小P需要说出他在这个区间内的士气和。如果他的士气和大于对手的士气和,那么他能得一分。在q次对决之后,双方得分较多的为获胜方。

在新国际象棋种有3种可以影响战局的操作:

魔术师:通过膜法将自己棋盘部分的第i个士兵与第j个士兵交换。
音乐家:通过高昂的歌声使自己棋盘部分的l到r的区间内士兵士气值加dis。
盗贼:盗取对手第i个士兵的士气值,并把它的士气值加到己方第i个士兵上。

小P带着自己的好友小Y来玩新国际象棋。

输入格式

第一行两个整数,n,m代表棋盘是2*n的,影响战局的操作数与对决数之和为m个

接下来两行,每行n个整数,分别代表自己和对手的初始士气值。

接下来m行,每行是下面有以下几种情况:

mig N x y:小"N"将自己棋盘部分的第x个士兵与第y个士兵交换,例如mig Y 2 5
mus N x y z:小"N"将自己棋盘部分的x到y的区间内士兵士气值加z,例如mus Y  1 3 2
sto N x y:小"N"盗取对手第x个士兵的士气值,并把它的士气值加到己方第y个士兵上,例如sto P 1 5
pk x y:对决双方区间[x,y]

输出格式

对于每次对决都出一次。

每输出一次包含两部分:
第一部分表示获胜的是小P还是小Y,若是小P则输出P,若是小Y则输出Y。
第二部分输出获胜方的区间和。
两个部分输出以一个空格隔开,例如Y 7

最后再输出最终获胜方,输出获胜者"is winner!",例如"little Y is winner!"

如果双方平局,则输出"five five open"。

样例

input1

5 5
1 3 2 5 1
1 3 2 5 1
mig P 3 2
mus Y 1 4 2
pk 1 3
sto P 1 5
pk 2 5

output1

Y 12
Y 17
little Y is winner!

input2

5 10
33702 7831 40840 14560 27164 
13691 20836 5480 2948 11791 
sto P 5 1
pk 2 5
pk 1 5
mig P 5 3
sto P 4 1
mig Y 2 5
mus P 2 3 148
sto P 4 3
pk 1 5
pk 1 1

output2

P 90395
P 135888
P 139132
P 48441
little P is winner!

数据范围与提示

对于百分之三十的数据: 1<=n,m<=1000。

对于另外百分之二十的数据: 没有sto和mig操作。

对于全部数据:1<=n,m<=200005。

题目链接、

线段树板子题、调了半天bug,发现有个 == 写成 = 了orz

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+7;
struct node{
    int l,r;
    ll val,lazy;
    void update(ll x){
        lazy += x;
        val += 1ll*(r-l+1)*x;
    }
}tree[2][maxn<<2];
ll flag,a[2][maxn];
void push_up(int x){tree[flag][x].val = tree[flag][x<<1].val+tree[flag][x<<1|1].val;}
void push_down(int x){
    if(tree[flag][x].lazy){
        tree[flag][x<<1].update(tree[flag][x].lazy);
        tree[flag][x<<1|1].update(tree[flag][x].lazy);
        tree[flag][x].lazy = 0;
    }
}
void build(int x,int l,int r){
    tree[flag][x].l = l,tree[flag][x].r = r;
    tree[flag][x].lazy = tree[flag][x].val = 0;
    if(l != r){
        int mid = (l+r)/2;
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
        push_up(x);
    }else tree[flag][x].val = a[flag][l];
}
void update(int x,int l,int r,ll val){
    int L = tree[flag][x].l,R = tree[flag][x].r;
    if(l<=L && R<=r)tree[flag][x].update(val);
    else{
        int mid = (L+R)/2;
        push_down(x);
        if(l<=mid) update(x<<1,l,r,val);
        if(r>mid) update(x<<1|1,l,r,val);
        push_up(x);
    }
}
ll query(int x,int l,int r){
    int L = tree[flag][x].l,R = tree[flag][x].r;
    if(l<=L && R<=r)return tree[flag][x].val;
    else{
        int mid = (L+R)/2;
        ll ans = 0;
        push_down(x);
        if(l<=mid) ans += query(x<<1,l,r);
        if(r>mid) ans += query(x<<1|1,l,r);
        push_up(x);
        return ans;
    }
}
char op[10],per[10];
int ans[2] = {0};
void pk(ll &t1,ll &t2,int x,int y){
    flag = 0,t1 = query(1,x,y);
    flag = 1,t2 = query(1,x,y);
}
void sto(int x,int y){
    ll t1 = query(1,x,x);
    update(1,x,x,-t1);
    flag = flag^1;
    update(1,y,y,t1);
}
void mig(int x,int y){
    if(x == y)return;
    ll t1 = query(1,x,x);
    ll t2 = query(1,y,y);
    update(1,x,x,t2-t1);
    update(1,y,y,t1-t2);
}
int main(){
    freopen("chess.in","r",stdin);
    freopen("chess.out","w",stdout);
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)scanf("%d",&a[0][i]);//p
    for(int i=1;i<=n;i++)scanf("%d",&a[1][i]);
    flag = 0,build(1,1,n),flag = 1,build(1,1,n);
    while(q--){
        int x,y;
        ll z;
        scanf("%s",op);
        if(op[0] == 'p')
            scanf("%d%d",&x,&y);
        else
            scanf("%s%d%d",per,&x,&y);

        if(op[0] == 'p'){
            ll t1,t2;
            pk(t1,t2,x,y);
            if(t1 == t2) continue;
            if(t1>t2)ans[0]++;
            else ans[1]++;
            //ans[t1<t2]++;
            printf("%c %lld\n",t1>t2?'P':'Y',max(t1,t2));
        }else if(op[0] == 's'){
            flag = (per[0] == 'P')?1:0;
            sto(x,y);
        }else if(op[1] == 'i'){
            flag = (per[0] == 'P')?0:1;
            mig(x,y);
        }else{
            scanf("%lld",&z);
            flag = (per[0] == 'P')?0:1;
            update(1,x,y,z);
        }
    }
    if(ans[0] == ans[1])return 0*printf("five five open\n");
    printf("little %c is winner!\n",ans[0]>ans[1]?'P':'Y');
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值