1.题目描述:
链接:https://www.nowcoder.com/acm/contest/160/D
来源:牛客网
给出一个长度为n的整数序列a1,a2,...,an,进行m次操作,操作分为两类。
操作1:给出l,r,v,将al,al+1,...,ar分别加上v;
操作2:给出l,r,询问
这题想一会了没想出来,也就没做了,看了别人的代码后,才发现我任然是个蒟蒻啊!(我好菜啊!)
其实不难看出在a[l...r]+=v后区间求和下面的特点:
没修改前:a[l...r]的正弦和等于
加上v后:a[l...r]+=v的正弦和为,刚好和就是没修改之前a[l...r]的正弦和、余弦和,所以需要预设两个数组保存之前的值即可。
修改后a[l...r]+=v的余弦和为。
ac代码如下:
#include<iostream>
#include<cstdio>
#include<cmath>
typedef long long LL;
const int maxn=2e5+5;
using namespace std;
LL a[maxn],lazy[maxn<<2];
double cosval[maxn<<2],sinval[maxn<<2];
int n,m;
double sintmp,costmp;
void pushUp(int rt)
{
sinval[rt]=sinval[rt<<1]+sinval[rt<<1|1];
cosval[rt]=cosval[rt<<1]+cosval[rt<<1|1];
}
void pushDown(int rt)
{
if(lazy[rt]){
lazy[rt<<1]+=lazy[rt];
lazy[rt<<1|1]+=lazy[rt];
sintmp=sinval[rt<<1];
costmp=cosval[rt<<1];
sinval[rt<<1]=sintmp*cos(lazy[rt])+costmp*sin(lazy[rt]);
cosval[rt<<1]=costmp*cos(lazy[rt])-sintmp*sin(lazy[rt]);
sintmp=sinval[rt<<1|1];
costmp=cosval[rt<<1|1];
sinval[rt<<1|1]=sintmp*cos(lazy[rt])+costmp*sin(lazy[rt]);
cosval[rt<<1|1]=costmp*cos(lazy[rt])-sintmp*sin(lazy[rt]);
lazy[rt]=0;
}
}
void build(int l,int r,int rt)
{
if(l==r){
sinval[rt]=sin(a[l]);
cosval[rt]=cos(a[l]);
return ;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
pushUp(rt);
}
void upDate(int L,int R,int C,int l,int r,int rt)
{
if(L<=l&&r<=R){
lazy[rt]+=C;
sintmp=sinval[rt];
costmp=cosval[rt];
sinval[rt]=sintmp*cos(C)+costmp*sin(C);
cosval[rt]=costmp*cos(C)-sintmp*sin(C);
return ;
}
int mid=(l+r)>>1;
pushDown(rt);
if(L<=mid) upDate(L,R,C,l,mid,rt<<1);
if(R>mid) upDate(L,R,C,mid+1,r,rt<<1|1);
pushUp(rt);
}
double query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R) return sinval[rt];
int mid=(l+r)>>1;
pushDown(rt);
double res=0;
if(L<=mid) res+=query(L,R,l,mid,rt<<1);
if(R>mid) res+=query(L,R,mid+1,r,rt<<1|1);
return res;
}
int main()
{
int op,l,r,v;
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,n,1);
scanf("%d",&m);
while(m--){
scanf("%d%d%d",&op,&l,&r);
if(op==1){
scanf("%d",&v);
upDate(l,r,v,1,n,1);
}
if(op==2) printf("%.1lf\n",query(l,r,1,n,1));
}
}
return 0;
}
2.然后又是一道我等蒟蒻a不了的题。
题目连接:https://vjudge.net/contest/243288#problem/I
题目大意也是区间修改求和,只是修改是对区间内的每个值开方。
个人理解的是如果区间内的值都为1,就不用修改了,否则就要在待修改区间利用循环进行单点更新。
直接上代码:
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define maxn 1000006
__int64 a[maxn+100],sum;
struct node{
int l,r;
__int64 sum;
}b[16*maxn];
void build(int l,int r,int i)
{
int mid;
b[i].l=l;b[i].r=r;
if(l==r){
b[i].sum=a[l];return;
}
mid=(l+r)/2;
build(l,mid,i*2);
build(mid+1,r,i*2+1);
b[i].sum=b[i*2].sum+b[i*2+1].sum;
}
void update1(int id,int i)
{
int mid;
if(b[i].l==b[i].r){
b[i].sum=a[b[i].l]=(int)(sqrt(1.0*a[b[i].l]));
return;
}
mid=(b[i].l+b[i].r)/2;
if(id>mid)update1(id,i*2+1);
else update1(id,i*2);
b[i].sum=b[i*2].sum+b[i*2+1].sum;
}
void update(int l,int r,int i)
{
int mid,j;
if(b[i].l==l && b[i].r==r){
if(b[i].sum==b[i].r-b[i].l+1)return;
for(j=b[i].l;j<=b[i].r;j++){
if(a[j]==1)continue;
update1(j,1);
}
return;
}
mid=(b[i].l+b[i].r)/2;
if(r<=mid)update(l,r,i*2);
else if(l>mid)update(l,r,i*2+1);
else {
update(l,mid,i*2);
update(mid+1,r,i*2+1);
}
}
void question(int l,int r,int i)
{
int mid;
if(b[i].l==l && b[i].r==r){
sum+=b[i].sum;return;
}
mid=(b[i].l+b[i].r)/2;
if(r<=mid)question(l,r,i*2);
else if(l>mid)question(l,r,i*2+1);
else {
question(l,mid,i*2);
question(mid+1,r,i*2+1);
}
}
int main()
{
int n,m,i,j,d,c,e,num1=0,temp;
while(scanf("%d",&n)!=EOF)
{
num1++;
printf("Case #%d:\n",num1);
for(i=1;i<=n;i++){
scanf("%I64d",&a[i]);
}
build(1,n,1);
scanf("%d",&m);
for(i=1;i<=m;i++){
scanf("%d%d%d",&c,&d,&e);
if(d>e){
temp=d;d=e;e=temp;
}
if(c==0)update(d,e,1);
else{
sum=0;
question(d,e,1);
printf("%I64d\n",sum);
}
}
printf("\n");
}
return 0;
}