考试B 冰雪奇缘改版 多边形剖梯形+线段树维护区间

从天而降很多个多边形,现在有n(1<=n<=25000)个询问,询问区间[l,r]之间多边形的面积

第一行表示数据组数T
每一组数据第一行包含一个整数n,表示操作的数量

R P 表示有一个多边形出现了,这个多边形有p个点,接下来的一行有2*p个数,以逆时针方向给出多边形的形状
Q A B 查询区间[A,B]的面积

Sample Input
1
7
Q 1 100
R 4
10 10 11 10 13 11 12 11
Q 10 11
Q 1 100
R 3
100 20 120 20 110 30
Q 1 100
Q 12 120

Sample Output
0.000
0.250
1.000
1.000
100.250

Hint:无小数据


把原来的梯形变成了多边形,但是,其实仔细观察后可以发现任意一个多边形都可以剖成多个梯形,一个重要的技巧就是,因为数据保证是逆时针读入,而只要我们花一个图就可以轻松发现,当从左往右枚举顶点的时候,把两个顶点之间与过最低点的水平线组成的一个直角梯形作为负面积,相反从右往左便利时候的构成的直角梯形作为正面积,然后用正面积减掉负面积就可以得到多边形的面积,好了,这就转化成为最开始的冰雪奇缘的问题了。这也是一个很重要的技巧吧。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ls u<<1,l,mid
#define rs u<<1|1,mid,r
#define maxn 25020
#include<map>
using namespace std;
void init(){
	freopen("B.in","r",stdin);
	freopen("B.out","w",stdout);
}

int n,cur[maxn*10],tot,cnt;
struct node{
	int l,r;
	double len,ladd,radd,s;
}nod[maxn * 4];
struct question{
	int a[6],b[6],flag,n,id,Min;
	bool operator <(const question& b)const{return id<b.id;}
}que[maxn*9];
int ttot;
struct new_question{
	double h1,h2;
	int x1,x2,id;
	bool operator<(const new_question& b)const{return id<b.id;}
	new_question():id(0){}
}ne[maxn*9];


void change(int i){//把 多边形变成梯形  
	for(int j=2;j<=que[i].n;j++){
		if(que[i].a[j]>que[i].a[j-1]){
			ne[++tot].h1=-(que[i].b[j-1]-que[i].Min),ne[tot].h2=-(que[i].b[j]-que[i].Min);
			ne[tot].x1=que[i].a[j-1];ne[tot].x2=que[i].a[j];
		}
		else {
			ne[++tot].h1=que[i].b[j]-que[i].Min,ne[tot].h2=que[i].b[j-1]-que[i].Min;
			ne[tot].x1=que[i].a[j];ne[tot].x2=que[i].a[j-1];
		}
	}
	ne[++tot].h1=que[i].b[1]-que[i].Min,ne[tot].h2=que[i].b[que[i].n]-que[i].Min;
	ne[tot].x1=que[i].a[1];ne[tot].x2=que[i].a[que[i].n];
}
bool cmp(int a,int b){return a<b;}
void front(){
	sort(cur+1,cur+1+cnt,cmp);//离散化横坐标 
	cnt=unique(cur+1,cur+1+cnt)-cur-1;
	
	//把多边形变成直角梯形
	
	for(int i=1;i<=n;i++){
		if(que[i].flag==1){
			change(i);
			
		}
		else {
			ne[++tot].id=24;
			ne[tot].x1=que[i].a[1],ne[tot].x2=que[i].b[1];
		}
	} 
}
void build(int u,int l,int r){  
    nod[u].ladd=nod[u].radd=nod[u].s=0;  nod[u].l=l,nod[u].r=r;  nod[u].len=cur[r]-cur[l];  
    if(l==r-1){  
        return ;  
    }  
    int mid=l+r>>1;  
    build(ls);  
    build(rs);  
}  
void push_up(int u){  
    int ll=u<<1,rr=u<<1|1;
    nod[u].s=nod[ll].s+nod[rr].s;  
}  
double Q(int x,double y,int a,double b,int mid){  
    return (double)y+(b-y)*1.0*(cur[mid]-cur[x])*1.0/(cur[a]-cur[x])*1.0;  
}  
void push_down(int u){  
    if(nod[u].ladd==0&&nod[u].radd==0)return ;  
    double x=Q(nod[u].l,nod[u].ladd,nod[u].r,nod[u].radd,nod[u].r+nod[u].l>>1);  
    int ll=u<<1,rr=u<<1|1;
    nod[ll].ladd+=nod[u].ladd;  
    nod[ll].radd+=x;  
    nod[rr].radd+=nod[u].radd;  
    nod[rr].ladd+=x;  
    nod[ll].s+=(nod[u].ladd+x)*nod[ll].len/2.0;  
    nod[rr].s+=(x+nod[u].radd)*nod[rr].len/2.0;  
    nod[u].ladd=nod[u].radd=0;  
}  
void updata(int u,int l,int r,int x,int y,double add1,double add2){  
    if(l==x&&r==y){  
        nod[u].s+=(add1+add2)*nod[u].len/2.0;  
        nod[u].ladd+=add1;nod[u].radd+=add2;  
        return;  
    }  
    push_down(u);  
    int mid=l+r>>1;  
    if(x>=mid)updata(rs,x,y,add1,add2);  
    else if(y<=mid)updata(ls,x,y,add1,add2);  
    else{  
        updata(ls,x,mid,add1,Q(x,add1,y,add2,mid));
		updata(rs,mid,y,Q(x,add1,y,add2,mid),add2);  
    }  
    push_up(u);  
}  
  
double query(int u,int l,int r,int x,int y){  
    if(x==l&&r==y){  return nod[u].s;}  
    push_down(u);  
    int mid=l+r>>1;  
    if(x>=mid)return query(rs,x,y);  
    else if(y<=mid)return query(ls,x,y);  
    else return query(ls,x,mid)+query(rs,mid,y);  
}  

int main(){
	init();
	int T=1;
	while(T--){
		tot=cnt=ttot=0;
		scanf("%d",&n);
		char s[5];
		for(int i=1;i<=n;i++){
			scanf("%s",s);
			if(s[0]=='Q'){
				que[i].flag=0,scanf("%d%d",&que[i].a[1],&que[i].b[1]);//0是查询 
				cur[++cnt]=que[i].a[1],cur[++cnt]=que[i].b[1];
			}
			else {
				que[i].flag=1;//1是多边形 
				scanf("%d",&que[i].n);
				for(int j=1;j<=que[i].n;j++){
					scanf("%d%d",&que[i].a[j],&que[i].b[j]);
					que[i].Min=min(que[i].Min,que[i].b[j]);
					cur[++cnt]=que[i].a[j];
				}
			}
		}
		front();
		build(1,1,cnt); 
		for(int i=1;i<=tot;i++){
			if(ne[i].id==24){
				printf("%.3lf\n",query(1,1,cnt,lower_bound(cur+1,cur+1+cnt,ne[i].x1)-cur,lower_bound(cur+1,cur+1+cnt,ne[i].x2)-cur));
			}
			else {
				updata(1,1,cnt,lower_bound(cur+1,cur+1+cnt,ne[i].x1)-cur,lower_bound(cur+1,cur+1+cnt,ne[i].x2)-cur,(double)ne[i].h1,(double)ne[i].h2);  
			}
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值