題意:有T組測試資料,每組資料有N個操作,(1)“R P”,表示掉下了一個P邊形,接下來的一行裡,給出這P個點的座標——首先是最左邊的點,然後從這點開始逆時針給出其他點。(2)"Q A B“,查詢數軸上區間[A,B]內面積的和。
易知,圖1裡的那個三角形的面積是通過,圖2裡紅色的面積加3裡綠色的面積,然後減去圖4裡黃色的面積。
這些圖形都可以轉化成梯形,即在一段區間[A,B]裡,A加上首項為add1,B加上末項為add2,長度為B-A+1,公差是(add2-add1)/(B-A+1)的等差數列。
我們從最左邊的那一點開始遍曆,如果當前點的x座標小於它的下一點的x座標,那麼就減去由當前點、下一點以及數軸構成的梯形的面積,反之則加上。那麼問題就是延遲標記是什麼,如何傳遞。這就和 Uva 12436 Rip Van Winkle's Code這道題很類似(解題報告Here)。等差數列疊加了,還是等差數列,性質沒有改變。所以線上段樹的結點裡,記錄左端點要加多少add1,右端點要加多少add2,以及公差step。向下傳遞的時候,將區間分解成兩部分,區間中點要加多少,可以通過等差數列的分工計算出來。
#include <iostream>#include <cstdio>#include <cstring>#include <vector>#include <map>#include <algorithm>using namespace std;#define LL(x) (x<<1)#define RR(x) (x<<1|1)#define MID(a,b) (a+((b-a)>>1))const int N=125010;struct node{int lft,rht,len;double add1,add2,step,sum;int mid(){return MID(lft,rht);}void init() { add1=add2=step=sum=0; }void fun(double a,double b,double c){add1+=a;add2+=b; step+=c;sum+=(a+b)*len/2;}};vector<int> sca;map<int,int> H;struct OP{int type,n;int x[6],y[6];void get(){char str[5];scanf("%s",str);if(str[0]=='R'){type=0;scanf("%d",&n);for(int i=0;i<n;i++){scanf("%d%d",&x[i],&y[i]);sca.push_back(x[i]);}}else{type=1;scanf("%d%d",&x[0],&y[0]);sca.push_back(x[0]);sca.push_back(y[0]);}}}op[N/5];struct Segtree{node tree[N*4];double calu(int st,int ed,double add1,double step){int len=sca[ed]-sca[st];return add1+len*step;}void PushUp(int ind){tree[ind].sum=tree[LL(ind)].sum+tree[RR(ind)].sum;}void PushDown(int ind){double add1=tree[ind].add1,add2=tree[ind].add2,step=tree[ind].step;double tmp=calu(tree[ind].lft,tree[ind].mid(),add1,step);tree[LL(ind)].fun(add1,tmp,step);tree[RR(ind)].fun(tmp,add2,step);tree[ind].add1=tree[ind].add2=tree[ind].step=0;}void build(int lft,int rht,int ind){tree[ind].lft=lft;tree[ind].rht=rht;tree[ind].init();tree[ind].len=sca[rht]-sca[lft];if(lft+1!=rht){int mid=tree[ind].mid();build(lft,mid,LL(ind));build(mid,rht,RR(ind));}}void updata(int st,int ed,int ind,double add1,double add2,double step){int lft=tree[ind].lft,rht=tree[ind].rht;if(st<=lft&&rht<=ed) tree[ind].fun(add1,add2,step);else{PushDown(ind);int mid=tree[ind].mid();if(ed<=mid) updata(st,ed,LL(ind),add1,add2,step);else if(st>=mid) updata(st,ed,RR(ind),add1,add2,step);else{double tmp=calu(st,mid,add1,step);updata(st,mid,LL(ind),add1,tmp,step);updata(mid,ed,RR(ind),tmp,add2,step);}PushUp(ind);}}double query(int st,int ed,int ind){int lft=tree[ind].lft,rht=tree[ind].rht;if(st<=lft&&rht<=ed) return tree[ind].sum;else{PushDown(ind);int mid=tree[ind].mid();double sum=0;if(st<mid) sum+=query(st,ed,LL(ind));if(ed>mid) sum+=query(st,ed,RR(ind));PushUp(ind);return sum;}}}seg;int main(){int t;scanf("%d",&t);while(t--){sca.clear(); H.clear();int n;scanf("%d",&n);for(int i=0;i<n;i++) op[i].get();sort(sca.begin(),sca.end());sca.erase(unique(sca.begin(),sca.end()),sca.end());for(int i=0;i<(int)sca.size();i++) H[sca[i]]=i;seg.build(0,(int)sca.size()-1,1);for(int i=0;i<n;i++){int x1,y1,x2,y2;if(op[i].type==0){for(int j=0;j<op[i].n;j++){x1=op[i].x[j];y1=op[i].y[j];x2=op[i].x[(j+1)%op[i].n];y2=op[i].y[(j+1)%op[i].n];if(x1>x2) swap(x1,x2),swap(y1,y2);else y1=-y1,y2=-y2;double step=(y1*1.-y2*1.)/(x1*1.-x2*1.);seg.updata(H[x1],H[x2],1,y1,y2,step);}}else{x1=op[i].x[0],y1=op[i].y[0];printf("%.3lf\n",seg.query(H[x1],H[y1],1));}}}return 0;}