HDU3340 Rain in ACStar (线段树维护等差数列)
对于这题,首先我们要明确的一点是,直接求面积肯定是不行的,所以要转化求,我们发现,其实整个多边形的面积就是与x轴所形成的两个矩形的差
而矩形的面积就可以用(a+b)*h/2来做,h就是相邻的x的差,那么只需要维护上底和下底就行了,我们发现,其实只需要维护一个等差数列就行了,这点很巧妙
因为我们的y值区别其实就是线性的关系,另外我们要知道,两个等差数列的和也是等差数列,这样我们就可以用线段树维护区间求y了。
对于多边形,在上面的边应该加,在下面的边应该减,根据输入,其实就是x1<x2的要减,否则是加,所以我们维护四个值即可,一个是首项,一个是末项,一个是公差,一个是总面积
本题数据很大,所以需要离散化。这里需要注意的是,如果处理区间问题,那么在更新的时候需要更新l和r-1而不是r,因为我们维护的是区间,如果不这样,会在mid的时候漏掉一段。
比如经典的扫描线问题等,都是需要r-1的,而如果我们单纯维护的一段点的话,就不需要-1,这里需要对每个题进行讨论,显然这题是真正意义上维护区间的。
这题不存在覆盖之类的问题,这需要对题意仔细理解。另外,我们知道,对于普通的区间修改,修改的时候值是不变的,但是等差数列不一样,因为如果在中间断开,那么对于两边修改的值是不一样的
如果不理解这句话,可以根据我modify函数的代码进行理解。
#include<iostream> #include<queue> #include<map> #include<vector> #include<cstdio> #include<algorithm> #include<stack> #include<string> #include<cstring> #include<set> using namespace std; typedef long long ll; const int N=1e5+10; struct qi{ int l[6]; int r[6]; string s; int cnt; }q[N]; struct node{ int l,r; double sum; double d; double ld; double rd; }tr[N<<2]; vector<int> num; void pushup(int u){ tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum; } double cal(int l,int r,double x,double y){ int len=num[r]-num[l-1]; return x+len*y; } void pushdown(int u){ double add1=tr[u].ld,add2=tr[u].rd,step=tr[u].d; double tmp=cal(tr[u].l,(tr[u].l+tr[u].r)>>1,add1,step); tr[u<<1].ld+=add1,tr[u<<1].rd+=tmp,tr[u<<1].sum+=(num[tr[u<<1].r]-num[tr[u<<1].l-1])*(add1+tmp)/2,tr[u<<1].d+=step; tr[u<<1|1].ld+=tmp,tr[u<<1|1].rd+=add2,tr[u<<1|1].sum+=(num[tr[u<<1|1].r]-num[tr[u<<1|1].l-1])*(tmp+add2)/2,tr[u<<1|1].d+=step; tr[u].ld=tr[u].rd=tr[u].d=0; } void build(int u,int l,int r){ if(l==r){ tr[u]=(node){l,l,0,0,0,0}; } else{ tr[u]=(node){l,r}; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); } } void modify(int u,int l,int r,double y1,double y2,double x){ if(tr[u].l>=l&&tr[u].r<=r){ tr[u].ld+=y1; tr[u].rd+=y2; tr[u].d+=x; tr[u].sum+=(num[tr[u].r]-num[tr[u].l-1])*(y1+y2)/2; return ; } pushdown(u); int mid=tr[u].l+tr[u].r>>1; double tmp=cal(l,mid,y1,x); if(l>mid){ modify(u<<1|1,l,r,y1,y2,x); } else if(r<=mid){ modify(u<<1,l,r,y1,y2,x); } else{ modify(u<<1,l,mid,y1,tmp,x); modify(u<<1|1,mid+1,r,tmp,y2,x); } pushup(u); } double query(int u,int l,int r){ if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum; pushdown(u); int mid=tr[u].l+tr[u].r>>1; double res=0; if(l<=mid) res=query(u<<1,l,r); if(r>mid) res+=query(u<<1|1,l,r); return res; } int find(int x){ return lower_bound(num.begin(),num.end(),x)-num.begin()+1; } int main(){ int i,j; int t; cin>>t; while(t--){ int n; num.clear(); cin>>n; for(i=1;i<=n;i++){ string s; cin>>s; q[i].s=s; if(s=="R"){ int x; cin>>x; q[i].cnt=x; for(j=0;j<x;j++){ scanf("%d%d",&q[i].l[j],&q[i].r[j]); num.push_back(q[i].l[j]); } } else{ scanf("%d%d",&q[i].l[0],&q[i].r[0]); num.push_back(q[i].l[0]); num.push_back(q[i].r[0]); } } sort(num.begin(),num.end()); num.erase(unique(num.begin(),num.end()),num.end()); build(1,1,num.size()-1); for(i=1;i<=n;i++){ if(q[i].s=="R"){ for(j=0;j<q[i].cnt;j++){ int x1=q[i].l[j],y1=q[i].r[j]; int x2=q[i].l[(j+1)%q[i].cnt],y2=q[i].r[(j+1)%q[i].cnt]; if(x1>x2){ swap(x1,x2); swap(y1,y2); } else{ y1=-y1,y2=-y2; } double d=(1.0*y1-1.0*y2)/(1.0*x1-1.0*x2); int pos1=find(x1); int pos2=find(x2); modify(1,pos1,pos2-1,y1,y2,d); } } else{ int pos1=find(q[i].l[0]); int pos2=find(q[i].r[0]); printf("%.3f\n",query(1,pos1,pos2-1)); } } } }
没有人不辛苦,只有人不喊疼