BZOJ 3878 [AHOI&JSOI2014]奇怪的计算器 (线段树)

题面:BZOJ传送门 洛谷传送门

线段树好题

题目保证$a$一定是正整数,容易发现计算结果是单调的

我们把询问离线,并按照从小到大排序

某次操作可能导致某些位置达到边界$L/R$

根据单调性的结论

这些位置一定是从$1$向右扩展或者$Q$向左扩展

可以二分找到这个区间,然后区间覆盖

那么修改操作,归根结底是这$4$种操作:

1.区间加减 2.区间乘法 3.区间覆盖 4.区间每个位置加某个数*对应位置的固定权值

比较复杂,考虑抽象化这个问题,把它写成一个函数

$f(a,b,c)=a*f(a,b,c)+b*X_{i}+c$

上述四种操作变成

$1.f(1,0,x) 2.(x,0,0) 3.(0,0,x) 4.(1,x,0)$

我们只需要每次把值往里面带,然后用线段树维护这个函数就行了

注意下推标记的顺序 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #define N1 100010
  5 #define ll long long 
  6 using namespace std;
  7 
  8 
  9 int gint()
 10 {
 11     int ret=0,fh=1; char c=getchar();
 12     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
 13     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
 14     return ret*fh;
 15 }
 16 
 17 int n;
 18 ll ml,mr;
 19 struct node{int id,x;ll ans;}q[N1];
 20 int cmp1(node s1,node s2){return s1.x<s2.x;}
 21 int cmp2(node s1,node s2){return s1.id<s2.id;}
 22 int v[N1],p[N1],f[N1],m;
 23 
 24 struct SEG{
 25 #define M1 (N1<<2)
 26 ll mi[M1],ma[M1],a[M1],b[M1],c[M1];
 27 void pushup(int rt)
 28 {
 29     mi[rt]=mi[rt<<1];             
 30     ma[rt]=ma[rt<<1|1];
 31 }
 32 void pushdown(int l,int r,int rt)
 33 {
 34     int mid=(l+r)>>1;
 35     if(a[rt]==1&&!b[rt]&&!c[rt]) return;
 36     a[rt<<1]=a[rt]*a[rt<<1];
 37     a[rt<<1|1]=a[rt]*a[rt<<1|1];
 38     b[rt<<1]=a[rt]*b[rt<<1]+b[rt]; 
 39     b[rt<<1|1]=a[rt]*b[rt<<1|1]+b[rt]; 
 40     c[rt<<1]=a[rt]*c[rt<<1]+c[rt];
 41     c[rt<<1|1]=a[rt]*c[rt<<1|1]+c[rt];
 42     mi[rt<<1]=a[rt]*mi[rt<<1]+b[rt]*v[l]+c[rt];
 43     mi[rt<<1|1]=a[rt]*mi[rt<<1|1]+b[rt]*v[mid+1]+c[rt];
 44     ma[rt<<1]=a[rt]*ma[rt<<1]+b[rt]*v[mid]+c[rt];
 45     ma[rt<<1|1]=a[rt]*ma[rt<<1|1]+b[rt]*v[r]+c[rt];
 46     a[rt]=1; b[rt]=c[rt]=0;
 47 }
 48 void update(int L,int R,int l,int r,int rt,ll A,ll B,ll C)
 49 {
 50     if(L<=l&&r<=R) 
 51     {
 52         a[rt]=A*a[rt];
 53         b[rt]=A*b[rt]+B;  
 54         c[rt]=A*c[rt]+C;
 55         mi[rt]=A*mi[rt]+B*v[l]+C;
 56         ma[rt]=A*ma[rt]+B*v[r]+C;
 57         return;
 58     }
 59     int mid=(l+r)>>1;
 60     if(L<=mid) update(L,R,l,mid,rt<<1,A,B,C);
 61     if(R>mid) update(L,R,mid+1,r,rt<<1|1,A,B,C);
 62     pushup(rt);
 63 
 64 }
 65 ll calc1(int x,ll rt,ll A,ll B,ll C){return A*mi[rt]+B*v[x]+C;}
 66 ll calc2(int x,ll rt,ll A,ll B,ll C){return A*ma[rt]+B*v[x]+C;}
 67 ll de;
 68 int qleft(int l,int r,int rt,int A,int B,int C)
 69 {
 70     if(l==r){ if(calc2(r,rt,A,B,C)>ml) return l-1; return l; }
 71     int mid=(l+r)>>1; pushdown(l,r,rt); de=calc2(mid,rt<<1,A,B,C);
 72     if(calc2(mid,rt<<1,A,B,C)<=ml) return qleft(mid+1,r,rt<<1|1,A,B,C);
 73     else return qleft(l,mid,rt<<1,A,B,C);
 74 }
 75 int qright(int l,int r,int rt,int A,int B,int C)
 76 {
 77     if(l==r){ if(calc1(l,rt,A,B,C)<mr) return l+1; return l; }
 78     int mid=(l+r)>>1; pushdown(l,r,rt); de=calc1(mid+1,rt<<1|1,A,B,C);
 79     if(calc1(mid+1,rt<<1|1,A,B,C)>=mr) return qright(l,mid,rt<<1,A,B,C);
 80     else return qright(mid+1,r,rt<<1|1,A,B,C);
 81 }
 82 void build(int l,int r,int rt)
 83 {
 84     a[rt]=1; b[rt]=c[rt]=0;
 85     if(l==r){ mi[rt]=ma[rt]=v[l]; return; }
 86     int mid=(l+r)>>1;
 87     build(l,mid,rt<<1);
 88     build(mid+1,r,rt<<1|1);
 89     pushup(rt);
 90 }
 91 void print(int l,int r,int rt,node *s)
 92 {
 93     if(l==r){ s[l].ans=mi[rt]; return; }
 94     int mid=(l+r)>>1; pushdown(l,r,rt);
 95     print(l,mid,rt<<1,s); 
 96     print(mid+1,r,rt<<1|1,s);
 97 }
 98 ll query(int x,int l,int r,int rt)
 99 {
100     if(l==r) return mi[rt];
101     int mid=(l+r)>>1; pushdown(l,r,rt);
102     if(x<=mid) return query(x,l,mid,rt<<1);
103     else return query(x,mid+1,r,rt<<1|1);
104 }
105 }s;
106 
107 
108 int main()
109 {
110     scanf("%d%lld%lld",&n,&ml,&mr);
111     char str[10]; int i,j,l,r;
112     for(i=1;i<=n;i++) 
113     {
114         scanf("%s",str);
115         switch(str[0])
116         {
117             case '+': p[i]=1; break;
118             case '-': p[i]=2; break;
119             case '*': p[i]=3; break;
120             case '@': p[i]=4; break;
121         }
122         f[i]=gint();
123     }
124     scanf("%d",&m);
125     for(i=1;i<=m;i++) q[i].x=gint(),q[i].id=i;
126     sort(q+1,q+m+1,cmp1);
127     for(i=1;i<=m;i++) v[i]=q[i].x;
128     s.build(1,m,1);
129     s.query(1,1,m,1);
130     for(i=1;i<=n;i++)
131     {
132         switch(p[i])
133         {
134         
135         case 1:
136         { 
137             l=s.qright(1,m,1,1,0,f[i]),r=m;
138             if(l>1) s.update(1,l-1,1,m,1,1,0,f[i]); 
139             if(l<=r) s.update(l,r,1,m,1,0,0,mr); 
140             break;
141         }
142         case 2: 
143         {
144             l=s.qleft(1,m,1,1,0,-f[i]),r=m;
145             if(l>0) s.update(1,l,1,m,1,0,0,ml);
146             if(l<r) s.update(l+1,r,1,m,1,1,0,-f[i]); 
147             break;
148         }
149         case 3: 
150         {
151             l=s.qright(1,m,1,f[i],0,0),r=m;
152             if(l>1) s.update(1,l-1,1,m,1,f[i],0,0); 
153             if(l<=r) s.update(l,r,1,m,1,0,0,mr); 
154             break;
155         }
156         case 4: 
157         {
158             l=s.qright(1,m,1,1,f[i],0),r=m;
159             if(l>1) s.update(1,l-1,1,m,1,1,f[i],0); 
160             if(l<=r) s.update(l,r,1,m,1,0,0,mr);
161             break;
162         }
163         
164         }
165         
166     }
167     s.print(1,m,1,q);
168     sort(q+1,q+m+1,cmp2);
169     for(i=1;i<=m;i++) printf("%lld
",q[i].ans);
170     return 0;
171 }
原文地址:https://www.cnblogs.com/guapisolo/p/10326241.html