题目描述
小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;
}