BZOJ 3878 Ahoi2014 奇怪的计算器 线段树

来源:互联网 发布:网上模拟钢琴软件 编辑:程序博客网 时间:2024/05/21 19:01

题目大意:给定n个操作,每个操作有四种形式,操作之后若<L就变成L,>R就变成R,现在给定q个输入,求他们的输出

n,q<=10W

将这q个数建立线段树,四个操作都可以在线段树上完成

但是溢出怎么办呢?

容易发现若x<=y,那么操作过后x一定<=y

因为四个操作都是线性的,溢出也不会反转两个数的大小关系

那么我们可以预先将q个数排序 那么溢出的数一定是连续的两段 区间修改就行了

至于怎么找两端溢出的区间…… 每个节点维护一个区间最大值和最小值就好了

此外数据还是比较良心的 不会出现爆long long这种P事 放心写吧

这么简单的思路我他妈的居然写了整整四遍的代码- - 下次写代码之前一定要想清楚- - 至少TM先手模拟过样例啊QAQ

#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 100100using namespace std;int n,m,L,R;int q[M];long long a[M];struct Operation{int type,x;friend istream& operator >> (istream &_,Operation &o){char p[10];scanf("%s%d",p,&o.x);switch(p[0]){case '+':o.type=1;break;case '-':o.type=2;break;case '*':o.type=3;break;case '@':o.type=4;break;}return _;}}operations[M];struct Segtree{Segtree *ls,*rs;long long times_mark,k,b;long long min_num,max_num;Segtree():ls(0x0),rs(0x0),times_mark(1),k(0),b(0) {}void Build_Tree(int x,int y){int mid=x+y>>1;min_num=a[x];max_num=a[y];if(x==y) return ;(ls=new Segtree)->Build_Tree(x,mid);(rs=new Segtree)->Build_Tree(mid+1,y);}void Get_Mark(int x,int y,long long _,long long __,long long ___){min_num=_*min_num+__*a[x]+___;max_num=_*max_num+__*a[y]+___;times_mark*=_;k*=_;b*=_;k+=__;b+=___;}void Push_Down(int x,int y){int mid=x+y>>1;ls->Get_Mark(x,mid,times_mark,k,b);rs->Get_Mark(mid+1,y,times_mark,k,b);times_mark=1;k=b=0;}int Get_Ans(int x,int y,int pos){int mid=x+y>>1;if(x==y) return max_num;Push_Down(x,y);if(pos<=mid)return ls->Get_Ans(x,mid,pos);elsereturn rs->Get_Ans(mid+1,y,pos);}void Get_L(int x,int y){int mid=x+y>>1;if(x==y){Get_Mark(x,y,0,0,L);return ;}Push_Down(x,y);if(rs->min_num<L)ls->Get_Mark(x,mid,0,0,L),rs->Get_L(mid+1,y);elsels->Get_L(x,mid);min_num=ls->min_num;max_num=rs->max_num;}void Get_R(int x,int y){int mid=x+y>>1;if(x==y){Get_Mark(x,y,0,0,R);return ;}Push_Down(x,y);if(ls->max_num>R)rs->Get_Mark(mid+1,y,0,0,R),ls->Get_R(x,mid);elsers->Get_R(mid+1,y);min_num=ls->min_num;max_num=rs->max_num;}}*tree=new Segtree;int main(){int i;cin>>n>>L>>R;for(i=1;i<=n;i++)cin>>operations[i];cin>>m;for(i=1;i<=m;i++)scanf("%d",&q[i]),a[i]=q[i];sort(a+1,a+m+1);tree->Build_Tree(1,m);for(i=1;i<=n;i++){switch(operations[i].type){case 1:tree->Get_Mark(1,m,1,0,operations[i].x);break;case 2:tree->Get_Mark(1,m,1,0,-operations[i].x);break;case 3:tree->Get_Mark(1,m,operations[i].x,0,0);break;case 4:tree->Get_Mark(1,m,1,operations[i].x,0);break;}if(tree->min_num<L)tree->Get_L(1,m);if(tree->max_num>R)tree->Get_R(1,m);}for(i=1;i<=m;i++){int pos=lower_bound(a+1,a+m+1,q[i])-a;printf("%d\n",tree->Get_Ans(1,m,pos) );}return 0;}


0 0