T1:高速公路
题干:
$Y901$ 高速公路是一条重要的交通纽带,政府部门建设初期的投入以及使用期间的养护费用都不低,因此政府在这条高速公路上设立了许多收费站。
$Y901$ 高速公路是一条由 $N-1$ 段路以及 $N$ 个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1~N,从收费站 i 行驶到 i+1 (或从 i+1 行驶到 i )需要收取 V_i 的费用。高速路刚建成时所有的路段都是免费的。
政府部门根据实际情况,会不定期地对连续路段的收费标准进行调整,根据政策涨价或降价。
无聊的小 A 同学总喜欢研究一些稀奇古怪的问题,他开车在这条高速路上行驶时想到了这样一个问题:对于给定的 l , r ( l < r ),在第 l 个到第 r 个收费站里等概率随机取出两个不同的收费站 a 和 b ,那么从 a 行驶到 b 将期望花费多少费用呢?
第一行 2 个正整数 N , M ,表示有 N 个收费站, M 次调整或询问。接下来 M 行,每行将出现以下两种形式中的一种:
C l r v 表示将第 l 个收费站到第 r 个收费站之间的所有道路的通行费全部增加 v
Q l r 表示对于给定的 l , r ,要求回答小 A 的问题
所有 C 与 Q 操作中保证 1<= l < r <= N
题解:
这道题就是一个维护区间修改的线段树优化。我们发现权值是在边上,我们比较容易地就可以想到将边标号,用线段树维护边的权值。
我们考虑一下每一条小边的贡献:
$ans=\sum\limits_{i=l}^r a[i]*(r-i+1)*(i-l+1)$
(因为一旦一条路线的左右边界在这条小边的两侧,这条小边就会做贡献,所以就有后面的两个常数)
化简后可得:
$ans=(r−l+1−r*l)*sum_1+(r+l)*sum_2−sum_3$
$sum_1=\sum\limits_{i=l}^r a[i]$
$sum_2=\sum\limits_{i=1}^r a[i]*i$
$sum_3=\sum\limits_{i=1}^r a[i]*i^2$
线段树维护 sum_1、sum_2、sum_3 三个懒标记即可。
Code:
1 #include<cstdio> 2 #include<cstring> 3 #define $ 100010 4 #define ll long long 5 using namespace std; 6 ll m,n,ans1,ans2,gcd; 7 struct tree{ int l,r; ll i,i1,i2,lazy; }a[$*4]; 8 inline void pushup(int x,ll val){ 9 ll l=a[x].l, r=a[x].r; 10 a[x].lazy+=val; 11 a[x].i+=val*(r-l+1); 12 a[x].i1+=val*(r-l+1)*(l+r)/2; 13 a[x].i2+=val*(1ll*r*(r+1)*(2*r+1)-1ll*l*(l-1)*(2*l-1))/6; 14 } 15 inline void pushdown(int x){ 16 if(a[x].lazy==0) return ; 17 pushup(x<<1,a[x].lazy); pushup(x<<1|1,a[x].lazy); 18 a[x].lazy=0; 19 } 20 inline void build(int x,int l,int r){ 21 a[x].l=l; a[x].r=r; 22 if(a[x].l==a[x].r) return; 23 int mid=(a[x].l+a[x].r)>>1; 24 build(x<<1,l,mid); build(x<<1|1,mid+1,r); 25 } 26 inline void change(int x,int l,int r,ll val){ 27 if(l<=a[x].l&&a[x].r<=r){ pushup(x,val); return; } 28 pushdown(x); 29 int mid=(a[x].l+a[x].r)>>1; 30 if(l<=mid) change(x<<1,l,r,val); 31 if(mid<r) change(x<<1|1,l,r,val); 32 a[x].i=a[x<<1].i+a[x<<1|1].i; 33 a[x].i1=a[x<<1].i1+a[x<<1|1].i1; 34 a[x].i2=a[x<<1].i2+a[x<<1|1].i2; 35 } 36 inline ll query(int x,int l,int r,int opt,ll ans=0){ 37 if(l<=a[x].l&&a[x].r<=r){ 38 if(opt==0) return a[x].i; 39 if(opt==1) return a[x].i1; 40 if(opt==2) return a[x].i2; 41 } 42 pushdown(x); 43 int mid=(a[x].l+a[x].r)>>1; 44 if(l<=mid) ans+=query(x<<1,l,r,opt); 45 if(mid<r) ans+=query(x<<1|1,l,r,opt); 46 return ans; 47 } 48 inline ll Gcd(ll a,ll b){ return (b==0)?a:Gcd(b,a%b); } 49 signed main(){ 50 scanf("%lld%lld",&n,&m); build(1,1,n-1); 51 for(register int i=1,l,r,v;i<=m;++i){ 52 char s=getchar(); 53 while(s!=‘C‘&&s!=‘Q‘) s=getchar(); 54 if(s==‘C‘) scanf("%d%d%d",&l,&r,&v), change(1,l,r-1,1ll*v); 55 if(s==‘Q‘){ 56 scanf("%d%d",&l,&r); 57 ans1=query(1,l,r-1,1)*(l+r-1)-query(1,l,r-1,0)*r*(l-1)-query(1,l,r-1,2); 58 ans2=1ll*(r-l+1)*(r-l)/2; 59 gcd=Gcd(ans1,ans2); 60 printf("%lld/%lld\n",ans1/gcd,ans2/gcd); 61 } 62 } 63 }
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<vector> 7 #include<queue> 8 using namespace std; 9 #define int long long 10 const int N=1e5+10; 11 struct node{ 12 int l,r,s1,s2,s3,s4,s5,lazy;//i^2*s[i],i*s[i],s[i]; 13 }tr[N<<2]; 14 int ans1,ans2,ans3; 15 void down(int p){ 16 tr[p<<1].s1+=(tr[p<<1].r-tr[p<<1].l+1)*tr[p].lazy; 17 tr[p<<1|1].s1+=(tr[p<<1|1].r-tr[p<<1|1].l+1)*tr[p].lazy; 18 tr[p<<1].s2+=tr[p<<1].s4*tr[p].lazy; 19 tr[p<<1|1].s2+=tr[p<<1|1].s4*tr[p].lazy; 20 tr[p<<1].s3+=tr[p<<1].s5*tr[p].lazy; 21 tr[p<<1|1].s3+=tr[p<<1|1].s5*tr[p].lazy; 22 tr[p<<1].lazy+=tr[p].lazy; 23 tr[p<<1|1].lazy+=tr[p].lazy; 24 tr[p].lazy=0; 25 } 26 void build(int p,int l,int r){ 27 tr[p].l=l,tr[p].r=r; 28 if(l==r){ 29 tr[p].s4=l; 30 tr[p].s5=l*l; 31 return ; 32 } 33 int mid=(l+r)>>1; 34 build(p<<1,l,mid); 35 build(p<<1|1,mid+1,r); 36 tr[p].s4=tr[p<<1].s4+tr[p<<1|1].s4; 37 tr[p].s5=tr[p<<1].s5+tr[p<<1|1].s5; 38 } 39 void add(int l,int r,int val,int p){ 40 if(tr[p].l>=l&&tr[p].r<=r){ 41 tr[p].lazy+=val; 42 tr[p].s1+=(tr[p].r-tr[p].l+1)*val; 43 tr[p].s2+=tr[p].s4*val; 44 tr[p].s3+=tr[p].s5*val; 45 return ; 46 } 47 down(p); 48 int mid=(tr[p].l+tr[p].r)>>1; 49 if(l<=mid)add(l,r,val,p<<1); 50 if(r>mid) add(l,r,val,p<<1|1); 51 tr[p].s1=tr[p<<1].s1+tr[p<<1|1].s1; 52 tr[p].s2=tr[p<<1].s2+tr[p<<1|1].s2; 53 tr[p].s3=tr[p<<1].s3+tr[p<<1|1].s3; 54 } 55 void query(int p,int l,int r){ 56 if(l<=tr[p].l&&tr[p].r<=r){ 57 ans1+=tr[p].s1; 58 ans2+=tr[p].s2; 59 ans3+=tr[p].s3; 60 return ; 61 } 62 down(p); 63 int mid=(tr[p].l+tr[p].r)>>1; 64 if(l<=mid) query(p<<1,l,r); 65 if(r>mid) query(p<<1|1,l,r); 66 } 67 int gcd(int a,int b) {return b?gcd(b,a%b):a;} 68 signed main(){ 69 int n,m; 70 scanf("%lld%lld",&n,&m); 71 build(1,1,n-1); 72 for(int i=1;i<=m;i++){ 73 char ch[2];int l,r; 74 scanf("%s",ch); 75 if(ch[0]==‘C‘){ 76 int val; 77 scanf("%lld%lld%lld",&l,&r,&val); 78 add(l,r-1,val,1); 79 } 80 else{ 81 scanf("%lld%lld",&l,&r); 82 ans1=ans2=ans3=0; 83 query(1,l,--r); 84 int ans=-ans3+(l+r)*ans2+(r-l+1-l*r)*ans1; 85 ans*=2; 86 int res=(r-l+1)*(r-l+2); 87 int GCD=gcd(res,ans); 88 //ans/=GCD,res/=GCD; 89 printf("%lld/%lld\n",ans/GCD,res/GCD); 90 } 91 } 92 }
T2:CPU 监控
题干:
Bob 需要一个程序来监视 CPU 使用率。这是一个很繁琐的过程,为了让问题更加简单,Bob 会慢慢列出今天会在用计算机时做什么事。 Bob 会干很多事,除了跑暴力程序看视频之外,还会做出去玩玩和用鼠标乱点之类的事,甚至会一脚踢掉电源……这些事有的会让做这件事的这段时间内 CPU 使用率增加或减少一个值;有的事还会直接让 CPU 使用率变为一个值。
当然 Bob 会询问:在之前给出的事件影响下, CPU 在某段时间内,使用率最高是多少。有时候 Bob 还会好奇地询问,在某段时间内 CPU 曾经的最高使用率是多少。 为了使计算精确,使用率不用百分比而用一个整数表示。
不保证 Bob 的事件列表出了莫名的问题,使得使用率为负………………
输入格式:第一行一个正整数 T ,表示 Bob 需要监视 CPU 的总时间。
然后第二行给出 T 个数表示在你的监视程序执行之前, Bob 干的事让 CPU 在这段时间内每个时刻的使用率达已经达到了多少。
第三行给出一个数 E,表示 Bob 需要做的事和询问的总数。
接下来E行每行表示给出一个询问或者列出一条事件:
Q X Y : 询问从 X 到 Y 这段时间内CPU最高使用率
A X Y : 询问从 X 到 Y 这段时间内之前列出的事件使 CPU 达到过的最高使用率
P X Y Z : 列出一个事件这个事件使得从X到Y这段时间内 CPU 使用率增加 Z
C X Y Z : 列出一个事件这个事件使得从X到Y这段时间内 CPU 使用率变为 Z
时间的单位为秒,使用率没有单位。
X 和 Y 均为正整数(X <= Y),Z 为一个整数。
从 X 到 Y 这段时间包含第 X 秒和第 Y 秒。
保证必要运算在有符号 32 位整数以内。
题解:
这道题真的十分难想,当时想到了一个十分难实现的懒标记,还是错的。。。(懒标记需要有优先级,否则在寻找历史最大值与现有最大值时会算不全,懒标记的延迟十分难搞)多亏有学长的 ppt ,才顿悟打了出来。来解释一下:
这道题只需要 6 个懒标记,有 历史最大值、现有最大值、历史最大覆盖值、现有覆盖值、
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<algorithm> 5 #define $ 100010 6 #define int long long 7 #define inf 0x7ffffffffff 8 using namespace std; 9 int m,n,k,t,w[$],e; 10 struct tree{ int l,r,max,hmax,add,hadd,set,hset; }a[$*4]; 11 inline int max(int x,int y){ return x>y?x:y; } 12 inline int min(int x,int y){ return x<y?x:y; } 13 inline void pushdown(int x){ 14 a[x<<1].hmax=max(a[x<<1].hmax,a[x<<1].max+a[x].hadd); 15 if(a[x<<1].hset!=-inf) 16 a[x<<1].hset=max(a[x<<1].hset,a[x].hadd+a[x<<1].set); 17 else 18 a[x<<1].hadd=max(a[x<<1].hadd,a[x].hadd+a[x<<1].add); 19 a[x<<1].hmax=max(a[x<<1].hmax,a[x].hset); 20 a[x<<1].hset=max(a[x<<1].hset,a[x].hset); 21 if(a[x].add!=0){ 22 a[x<<1].max+=a[x].add; 23 a[x<<1].hmax=max(a[x<<1].hmax,a[x<<1].max); 24 if(a[x<<1].set==-inf) 25 a[x<<1].add+=a[x].add, a[x<<1].hadd=max(a[x<<1].hadd,a[x<<1].add); 26 else 27 a[x<<1].set+=a[x].add, a[x<<1].hset=max(a[x<<1].hset,a[x<<1].set); 28 } 29 else if(a[x].set!=-inf){ 30 a[x<<1].max=a[x].set; 31 a[x<<1].hmax=max(a[x<<1].hmax,a[x<<1].max); 32 a[x<<1].set=a[x].set; 33 a[x<<1].hset=max(a[x<<1].hset,a[x].set); 34 a[x<<1].add=0; 35 } 36 37 a[x<<1|1].hmax=max(a[x<<1|1].hmax,a[x<<1|1].max+a[x].hadd); 38 if(a[x<<1|1].hset!=-inf) 39 a[x<<1|1].hset=max(a[x<<1|1].hset,a[x].hadd+a[x<<1|1].set); 40 else 41 a[x<<1|1].hadd=max(a[x<<1|1].hadd,a[x].hadd+a[x<<1|1].add); 42 a[x<<1|1].hmax=max(a[x<<1|1].hmax,a[x].hset); 43 a[x<<1|1].hset=max(a[x<<1|1].hset,a[x].hset); 44 if(a[x].add!=0){ 45 a[x<<1|1].max+=a[x].add; 46 a[x<<1|1].hmax=max(a[x<<1|1].hmax,a[x<<1|1].max); 47 if(a[x<<1|1].set==-inf) 48 a[x<<1|1].add+=a[x].add, a[x<<1|1].hadd=max(a[x<<1|1].hadd,a[x<<1|1].add); 49 else 50 a[x<<1|1].set+=a[x].add, a[x<<1|1].hset=max(a[x<<1|1].hset,a[x<<1|1].set); 51 } 52 else if(a[x].set!=-inf){ 53 a[x<<1|1].max=a[x].set; 54 a[x<<1|1].hmax=max(a[x<<1|1].hmax,a[x<<1|1].max); 55 a[x<<1|1].set=a[x].set; 56 a[x<<1|1].hset=max(a[x<<1|1].hset,a[x].set); 57 a[x<<1|1].add=0; 58 } 59 60 a[x].set=a[x].hset=-inf; 61 a[x].add=a[x].hadd=0; 62 } 63 inline void build(int x,int l,int r){ 64 a[x].l=l; a[x].r=r; 65 a[x].max=a[x].hmax=a[x].set=a[x].hset=-inf; 66 a[x].add=a[x].hadd=0; 67 if(a[x].l==a[x].r){ a[x].max=a[x].hmax=w[l]; return; } 68 int mid=(a[x].l+a[x].r)>>1; 69 build(x<<1,l,mid); build(x<<1|1,mid+1,r); 70 a[x].max=max(a[x<<1].max,a[x<<1|1].max); 71 a[x].hmax=max(a[x<<1].hmax,a[x<<1|1].hmax); 72 } 73 inline void add(int x,int l,int r,int val){ 74 if(l<=a[x].l&&a[x].r<=r){ 75 a[x].max+=val; 76 a[x].hmax=max(a[x].hmax,a[x].max); 77 if(a[x].set==-inf) a[x].add+=val, a[x].hadd=max(a[x].hadd,a[x].add); 78 else a[x].set+=val, a[x].hset=max(a[x].hset,a[x].set); 79 return; 80 } 81 pushdown(x); 82 int mid=(a[x].l+a[x].r)>>1; 83 if(l<=mid) add(x<<1,l,r,val); 84 if(mid<r) add(x<<1|1,l,r,val); 85 a[x].max=max(a[x<<1].max,a[x<<1|1].max); 86 a[x].hmax=max(a[x<<1].hmax,a[x<<1|1].hmax); 87 } 88 inline void change(int x,int l,int r,int val){ 89 if(l<=a[x].l&&a[x].r<=r){ 90 a[x].max=a[x].set=val; 91 a[x].hmax=max(a[x].max,a[x].hmax); 92 a[x].hset=max(val,a[x].hset); 93 a[x].add=0; 94 return; 95 } 96 pushdown(x); 97 int mid=(a[x].l+a[x].r)>>1; 98 if(l<=mid) change(x<<1,l,r,val); 99 if(mid<r) change(x<<1|1,l,r,val); 100 a[x].max=max(a[x<<1].max,a[x<<1|1].max); 101 a[x].hmax=max(a[x<<1].hmax,a[x<<1|1].hmax); 102 } 103 inline int ask_max(int x,int l,int r,int ans=-inf){ 104 if(l<=a[x].l&&a[x].r<=r) return a[x].max; 105 pushdown(x); 106 int mid=(a[x].l+a[x].r)>>1; 107 if(l<=mid) ans=max(ans,ask_max(x<<1,l,r)); 108 if(mid<r) ans=max(ans,ask_max(x<<1|1,l,r)); 109 return ans; 110 } 111 inline int ask_hmax(int x,int l,int r,int ans=-inf){ 112 if(l<=a[x].l&&a[x].r<=r) return a[x].hmax; 113 pushdown(x); 114 int mid=(a[x].l+a[x].r)>>1; 115 if(l<=mid) ans=max(ans,ask_hmax(x<<1,l,r)); 116 if(mid<r) ans=max(ans,ask_hmax(x<<1|1,l,r)); 117 return ans; 118 } 119 signed main(){ 120 scanf("%lld",&t); 121 for(register int i=1;i<=t;++i) scanf("%lld",&w[i]); 122 build(1,1,t); 123 scanf("%lld",&e); 124 for(register int i=1,x,y,z;i<=e;++i){ 125 char s=getchar(); 126 while(s!=‘Q‘&&s!=‘A‘&&s!=‘P‘&&s!=‘C‘) s=getchar(); 127 if(s==‘Q‘) scanf("%lld%lld",&x,&y), printf("%lld\n",ask_max(1,x,y)); 128 if(s==‘A‘) scanf("%lld%lld",&x,&y), printf("%lld\n",ask_hmax(1,x,y)); 129 if(s==‘P‘) scanf("%lld%lld%lld",&x,&y,&z), add(1,x,y,z); 130 if(s==‘C‘) scanf("%lld%lld%lld",&x,&y,&z), change(1,x,y,z); 131 } 132 }
T3:
题干:
在 2016 年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。这个难题是这样子的:给出一个 1 到 n 的全排列,现在对这个全排列序列进行 m 次局部排序,排序分为两种:
1: ( 0 , l , r ) 表示将区间 [ l , r ] 的数字升序排序
2 :( 1 , l , r ) 表示将区间 [ l , r ] 的数字降序排序最后询问第 q 位置上的数字。
输入格式:输入数据的第一行为两个整数 n 和 m 。 n 表示序列的长度,m 表示局部排序的次数。1 <= n, m <= 10^5;第二行为 n 个整数,表示 1 到 n 的一个全排列。
接下来输入 m 行,每一行有三个整数 op , l , r , op 为 0 代表升序排序, op 为 1 代表降序排序, l , r 表示排序的区间。
最后输入一个整数 q,q 表示排序完之后询问的位置, 1 <= q <= n。1 <= n <= 10^5,1 <= m <= 10^5
输出格式:输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第 q 位置上的数字。
题解:
这道题想都没想就打了一个复杂度为 $\Theta(nmlog_2n)$ 的线段树优化桶排。。。(比快排还慢。。。)
题中说明了一定是一个全排列,桶排就给跪了。。。全排列代表没有重复的数,这就有答案单调性——二分答案。
我们可以二分
时间复杂度:$\Theta(mlog_2nlog_2ans)$
Code:
1 #include<cstdio> 2 #include<cstring> 3 #define $ 100100 4 using namespace std; 5 int m,n,k,t,sum[$],ans[$],tot,a[$],q,lp[$],rp[$],opt[$],minn,maxx,mid; 6 struct tree{ int val,l,r,lazy; }tr[$*4]; 7 inline void pushup(int x){ 8 tr[x].val=tr[x<<1].val+tr[x<<1|1].val; 9 } 10 inline void pushdown(int x){ 11 if(tr[x].lazy==-1) return; 12 tr[x<<1].lazy=tr[x<<1|1].lazy=tr[x].lazy; 13 tr[x<<1].val=(tr[x<<1].r-tr[x<<1].l+1)*tr[x].lazy; 14 tr[x<<1|1].val=(tr[x<<1|1].r-tr[x<<1|1].l+1)*tr[x].lazy; 15 tr[x].lazy=-1; 16 } 17 inline void build(int x,int l,int r){ 18 tr[x].l=l, tr[x].r=r; tr[x].lazy=-1; 19 if(l==r) return; 20 int mid=(tr[x].l+tr[x].r)>>1; 21 build(x<<1,l,mid), build(x<<1|1,mid+1,r); 22 } 23 inline void change(int x,int l,int r,int val){ 24 if(l<=tr[x].l&&tr[x].r<=r){ 25 tr[x].val=(tr[x].r-tr[x].l+1)*val; 26 tr[x].lazy=val; 27 return ; 28 } 29 pushdown(x); 30 int mid=(tr[x].l+tr[x].r)>>1; 31 if(l<=mid) change(x<<1,l,r,val); 32 if(mid+1<=r) change(x<<1|1,l,r,val); 33 pushup(x); 34 } 35 inline void pre(int x,int l,int r){ 36 if(l<=tr[x].l&&tr[x].r<=r&&tr[x].val){ 37 sum[tr[x].val]+=tr[x].r-tr[x].l+1;return; 38 } 39 pushdown(x); 40 int mid=(tr[x].l+tr[x].r)>>1; 41 if(l<=mid) pre(x<<1,l,r); 42 if(mid+1<=r) pre(x<<1|1,l,r); 43 pushup(x); 44 } 45 inline int query(int x,int l,int r,int ans=0){ 46 if(l<=tr[x].l&&tr[x].r<=r) return tr[x].val; 47 int mid=(tr[x].l+tr[x].r)>>1; 48 pushdown(x); 49 if(l<=mid) ans+=query(x<<1,l,r); 50 if(mid+1<=r) ans+=query(x<<1|1,l,r); 51 return ans; 52 } 53 inline void work(int optt,int l,int r){ 54 int tmp=query(1,l,r); 55 change(1,l,r,0); 56 if(!optt) change(1,r-tmp+1,r,1); 57 if(optt) change(1,l,l+tmp-1,1); 58 } 59 inline bool judge(int x){ 60 change(1,1,n,0); change(1,mid+1,n,1); 61 for(register int i=1;i<=m;++i) work(opt[i],lp[i],rp[i]); 62 return query(1,q,q); 63 } 64 signed main(){ 65 scanf("%d%d",&n,&m); build(1,1,n); 66 for(register int i=1;i<=n;++i) scanf("%d",&a[i]); 67 for(register int i=1;i<=m;++i) scanf("%d%d%d",&opt[i],&lp[i],&rp[i]); 68 scanf("%d",&q); 69 minn=1, maxx=n; 70 while(minn<maxx){ 71 mid=(minn+maxx)>>1; 72 if(judge(mid)) minn=mid+1; 73 else maxx=mid; 74 } 75 printf("%d\n",minn); 76 }
T4:
题干:
题解:
Code:
原文地址:https://www.cnblogs.com/OI-zzyy/p/11291364.html