(一)题面:
Problem description |
JuQueen is the super computer with the best performance allover Germany. It is on rank 8 in the famous top500 list with its 458 752 cores. It draws a lot of energy (up to 2 301 kW), so we want to reduce that by underclocking the unused cores. |
Input |
|
Output |
Output one line for every operation in the input. For change and groupchange print the changed number of steps, for state print the current state. |
Sample Input |
10 10 5 state 0 groupchange 2 9 7 state 9 groupchange 0 2 10 change 0 -5 4587520 10000 5 groupchange 0 4587010 9950 groupchange 23 4587000 42 groupchange 4710 4587001 -1000 state 1234560 groupchange 6666 3060660 10000 |
Sample Output |
0 7 7 3 -3 9950 42 -1000 8992 1008 |
(二)题目大意:
有C个数,O次操作,每次操作有三种可能:
①查询某个位置的值;
②将区间[l,r]的所有数+v;
③将某个位置的值-v。并且每个元素的值不能小于0且不能大于N。
若为操作①则输出查询位置的值;若为操作②或③则输出该操作实际能改变数值的大小(见样例)。
(三)解题思路:
①根据题意就可以知道这个题几乎是裸的线段树,包括单点区间修改和单点修改(可以转化为区间修改)。
②维护区间的最大值和最小值,每次进行操作的时候先根据最大值和最小值确定能修改的数值大小,再进行修改。
③考虑到原来的下标是从0~4587520,而总共的操作数最多只有5e5,即最多用到的坐标数不会超过1e6,我们可以将坐标离散化,然后再建树。
(四)具体代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<algorithm>
#define INF 1000000000
using namespace std;
const int maxn=500005;
int n,c,q,val,_Max,_Min;
struct Tree{
int L,R,_max,_min,lazy;
int mid(){return (L+R)>>1;}
}tree[maxn<<4];
struct Oper{
int l,r,v,o;
}op[maxn];
vector<int>V;
int getid(int x){return lower_bound(V.begin(),V.end(),x)-V.begin()+1;}
void BuildTree(int l,int r,int i){
tree[i].L=l;tree[i].R=r;
tree[i]._max=tree[i]._min=tree[i].lazy=0;
if(l==r)return;
int m=tree[i].mid();
BuildTree(l,m,i<<1);
BuildTree(m+1,r,i<<1|1);
}
void Push_down(int i){
if(tree[i].lazy){
tree[i<<1]._max+=tree[i].lazy;
tree[i<<1|1]._max+=tree[i].lazy;
tree[i<<1]._min+=tree[i].lazy;
tree[i<<1|1]._min+=tree[i].lazy;
tree[i<<1].lazy+=tree[i].lazy;
tree[i<<1|1].lazy+=tree[i].lazy;
tree[i].lazy=0;
}
}
void Push_up(int i){
tree[i]._max=max(tree[i<<1]._max,tree[i<<1|1]._max);
tree[i]._min=min(tree[i<<1]._min,tree[i<<1|1]._min);
}
void QueryTree(int l,int r,int i){
int L=tree[i].L,R=tree[i].R;
if(l<=L&&R<=r){
_Max=max(_Max,tree[i]._max);
_Min=min(_Min,tree[i]._min);
return;
}
Push_down(i);
int m=tree[i].mid();
if(r<=m)QueryTree(l,r,i<<1);
else if(l>m)QueryTree(l,r,i<<1|1);
else{
QueryTree(l,m,i<<1);
QueryTree(m+1,r,i<<1|1);
}
}
void UpdateTree(int l,int r,int i,int v){
int L=tree[i].L,R=tree[i].R;
if(l<=L&&R<=r){
tree[i]._max+=v;
tree[i]._min+=v;
tree[i].lazy+=v;
return;
}
Push_down(i);
int m=tree[i].mid();
if(r<=m)UpdateTree(l,r,i<<1,v);
else if(l>m)UpdateTree(l,r,i<<1|1,v);
else{
UpdateTree(l,m,i<<1,v);
UpdateTree(m+1,r,i<<1|1,v);
}
Push_up(i);
}
void scan_d(int &x){
int sig=1;x=0;
char ch=getchar();
while(ch!='-'&&(ch<'0')||(ch>'9'))ch=getchar();
if(ch=='-')sig=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+(ch&15),ch=getchar();
x*=sig;
}
int main(){
freopen("in.txt","r",stdin);
while(~scanf("%d%d%d",&n,&c,&q)){getchar();
for(int i=0;i<q;i++){
char Ch=getchar();
if(Ch=='s'){
scan_d(op[i].l);op[i].r=op[i].l;op[i].o=1;
V.push_back(op[i].l);
}
else{
scan_d(op[i].l);op[i].r=op[i].l;
if(Ch=='g')scan_d(op[i].r);scan_d(op[i].v);op[i].o=2;
V.push_back(op[i].l);V.push_back(op[i].r);
}
}
sort(V.begin(),V.end());
V.erase(unique(V.begin(),V.end()),V.end());
for(int i=0;i<q;i++){
op[i].l=getid(op[i].l);
op[i].r=getid(op[i].r);
}
BuildTree(1,V.size(),1);
for(int i=0;i<q;i++){
_Max=-1e9;_Min=1e9;
QueryTree(op[i].l,op[i].r,1);
if(op[i].o==1){printf("%d\n",_Max);}
else{
if(!op[i].v){printf("0\n");continue;}
else if(op[i].v>0)val=min(op[i].v,c-_Max);
else val=max(op[i].v,-_Min);
printf("%d\n",val);
UpdateTree(op[i].l,op[i].r,1,val);
}
}
}
return 0;
}
(五)总结:
其实这里主要想记录的是一个离散化的操作,当我们不在意值的具体大小而只关心值的相对大小时,将数据离散化可能可以很大程度地减少时间开支。线段树里面的离散化操作貌似还不少,平时需要多练。