P8105 [LCOI RI]Cow Dance 题解
little_cindy · · 题解
思路
这个题是对于subtask进行处理(有的不能同时得分,例如 subtask
subtask 1
暴力就好了。
subtask 2
维护区间旋转角度,区间和,线段树即可。
subtask 3
维护区间放大倍数,区间和,线段树即可。
subtask 4
维护区间平移,两个线段树即可。
subtask 5
暴力。
subtask 6
和正解几乎一样但有缺陷的做法。
subtask 7
留给常数较大的同正解相同的做法。
subtask 8
注意到区间旋转位似都可以拿矩阵维护,就相当于矩阵加和矩阵乘,或者用虚数维护。
对于平移操作,就是加上一个虚数。
对于旋转和位似操作,可以先把这个中心移到原点,再乘上一个虚数即可,维护区间加,区间乘即可。
复杂度
code
这一题比较良心,不用快读。
#include<bits/stdc++.h>
using namespace std;
#define maxn 300010
int n,m;
int x,y,a,b,p,q,opt;
const double eps=1e-6;
struct Cp{
double a,b;
Cp(double aa=0,double bb=0):a(aa),b(bb){}
Cp operator+(Cp x)const{return Cp(a+x.a,b+x.b);}
Cp operator-(Cp x)const{return Cp(a-x.a,b-x.b);}
Cp operator*(Cp x)const{return Cp(a*x.a-b*x.b,a*x.b+x.a*b);}
Cp operator*(int x)const{return Cp(a*x,b*x);}
bool operator==(double x)const{return fabs(b)<eps&&fabs(a-x)<eps;}
bool operator==(Cp x)const{return fabs(a-x.a)<eps&&fabs(b-x.b)<eps;}
void print(){
printf("%.6lf %.6lf\n",a,b);
}
};
Cp e(int a){
double r=a*3.14159265358979323846/180;
return Cp(cos(r),-sin(r));
}
struct sto_DX_orz{
int l,r;
Cp sum,mul,add;
}tree[maxn<<2];
void pushup(int x){
tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum;
}
void pushdown(int x){
if(!(tree[x].mul==1.0)){
tree[x<<1].add=tree[x<<1].add*tree[x].mul;
tree[x<<1|1].add=tree[x<<1|1].add*tree[x].mul;
tree[x<<1].sum=tree[x<<1].sum*tree[x].mul;
tree[x<<1|1].sum=tree[x<<1|1].sum*tree[x].mul;
tree[x<<1].mul=tree[x<<1].mul*tree[x].mul;
tree[x<<1|1].mul=tree[x<<1|1].mul*tree[x].mul;
tree[x].mul=Cp(1,0);
}
if(!(tree[x].add==0)){
tree[x<<1].add=tree[x<<1].add+tree[x].add;
tree[x<<1|1].add=tree[x<<1|1].add+tree[x].add;
tree[x<<1].sum=tree[x<<1].sum+tree[x].add*(tree[x<<1].r-tree[x<<1].l+1);
tree[x<<1|1].sum=tree[x<<1|1].sum+tree[x].add*(tree[x<<1|1].r-tree[x<<1|1].l+1);
tree[x].add=Cp(0,0);
}
}
void build(int x,int l,int r){
tree[x].l=l,tree[x].r=r;
tree[x].mul=Cp(1,0);
if(l==r){
int a,b;
cin>>a>>b;
tree[x].sum=Cp((double)a,(double)b);
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid),build(x<<1|1,mid+1,r);
pushup(x);
}
void change1(int x,int l,int r,Cp k){
if(tree[x].l>=l&&tree[x].r<=r){
tree[x].add=tree[x].add+k;
tree[x].sum=tree[x].sum+k*(tree[x].r-tree[x].l+1);
return;
}
pushdown(x);
int mid=(tree[x].l+tree[x].r)>>1;
if(l<=mid)change1(x<<1,l,r,k);
if(r>mid)change1(x<<1|1,l,r,k);
pushup(x);
}
void change2(int x,int l,int r,Cp k){
if(tree[x].l>=l&&tree[x].r<=r){
tree[x].add=tree[x].add*k;
tree[x].mul=tree[x].mul*k;
tree[x].sum=tree[x].sum*k;
return;
}
pushdown(x);
int mid=(tree[x].l+tree[x].r)>>1;
if(l<=mid)change2(x<<1,l,r,k);
if(r>mid)change2(x<<1|1,l,r,k);
pushup(x);
}
Cp ask(int x,int l,int r){
if(tree[x].l>=l&&tree[x].r<=r)return tree[x].sum;
pushdown(x);
int mid=(tree[x].l+tree[x].r)>>1;
Cp val;
if(l<=mid)val=(val+ask(x<<1,l,r));
if(r>mid)val=(val+ask(x<<1|1,l,r));
return val;
}
signed main(){
srand(time(NULL));
scanf("%d%d",&n,&m);
build(1,1,n);
while(m--){
scanf("%d%d%d",&opt,&x,&y);
if(opt==4){
Cp DX=ask(1,x,y);
DX.a/=(y-x+1),DX.b/=(y-x+1);
DX.print();
}else{
scanf("%d%d",&a,&b);
Cp A((double)a,(double)b);
if(opt==1)change1(1,x,y,A);
else{
scanf("%d",&p);
Cp E;
if(opt==2)E=e(p);
else scanf("%d",&q),E=Cp((double)p/q,0);
change2(1,x,y,E);
change1(1,x,y,A*(Cp(1,0)-E));
}
}
}
}