终于学到线段树了,以前看见很多这样的题,然后暴力,然后TTTTTT了,,,,
我并不打算写了,不过我看到一个非常好的博客,推荐给初学者
http://www.cnblogs.com/TenosDoIt/p/3453089.html#a
特别好玩!!!
最简单的板子(建树,区间最小(大)值,区间和,单节点更新,区间更新)
以0为根节点表示的是整个区间,向左右分叉,左面是左区间,右面是右区间
然后重复以上过程直到查到单个数才回溯,从而变成如上图的样子。
/*****最值*****/
void change(int root,int x,int k)//单点修改
{
int l=e[root].l;
int r=e[root].r;
int mid=(l+r)/2;
if(l==r)
{
e[root].sum+=k;
return ;
}
if(x<=mid)
change(root<<1,x,k);
else
change(root<<1|1,x,k);
e[root].sum=e[root<<1].sum+e[root<<1|1].sum;
}
int query(int root,int ql,int qr)//区间查询(求最值)
{
int l=e[root].l,r=e[root].r;
int mid=(l+r)/2;
int ans=-1;
if(ql<=l&&r<=qr)
{
return e[root].maxx;
}
if(ql<=mid)
ans=max(ans,query(root<<1,ql,qr));
if(mid<qr)
ans=max(ans,query(root<<1|1,ql,qr));
return ans;
}
/*****求和********/
void pushdown(int root)//求和更新
{
if(e[root].flag)
{
int l=e[root].l,r=e[root].r;
int mid=(l+r)/2;
e[root<<1].sum+=(e[root].flag*(mid-l+1));
e[root<<1].flag+=e[root].flag;//应该是+,易错
e[root<<1|1].sum+=(e[root].flag*(r-mid));
e[root<<1|1].flag+=e[root].flag;
e[root].flag=0;
}
}
int query(int root,int ql,int qr)//区间查询(求和)
{
int l=e[root].l;
int r=e[root].r;
int mid=(l+r)/2;
if(ql<=l&&r<=qr)
return e[root].sum;
int ans=0;
pushdown(root);//看是否需要
if(ql<=mid)
ans+=query(root<<1,ql,qr);
if(mid<qr)
ans+=query(root<<1|1,ql,qr);
return ans;
}
void update(int root,int ql,int qr,int k)//区间更新(求和)
{
int l=e[root].l,r=e[root].r;
int mid=(l+r)/2;
if(ql<=l&&r<=qr)
{
e[root].sum+=k*(r-l+1);
e[root].flag+=k;
return ;
}
pushdown(root);
if(ql<=mid)
update(root<<1,ql,qr,k);
if(mid<qr)
update(root<<1|1,ql,qr,k);
e[root].sum=e[root<<1].sum+e[root<<1|1].sum;//更新回溯
}
/******区间染色*****/
int ro[maxn];
int vis[maxn];
int ans;
void pushdown(int root)
{
if(ro[root]!=-1)
{
ro[root<<1]=ro[root];
ro[root<<1|1]=ro[root];
ro[root]=-1;
}
}
void update(int root,int l,int r,int ql,int qr,int k)
{
if(ql<=l&&r<=qr)
{
ro[root]=k;
return ;
}
pushdown(root);
int mid=(l+r)/2;
if(mid>=ql) update(root<<1,l,mid,ql,qr,k);
if(mid<qr) update(root<<1|1,mid+1,r,ql,qr,k);
}
void query(int root,int l,int r)
{
if(ro[root]!=-1)
{
int k=ro[root];
if(!vis[k])
{
ans++;
vis[k]=1;
}
return ;
}
if(l==r) return ;
int mid=(l+r)/2;
query(root<<1,l,mid);
query(root<<1|1,mid+1,r);
}
int l[maxn],r[maxn];
int m[maxn];
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
memset(m,0,sizeof(m));
memset(ro,-1,sizeof(ro));
memset(vis,0,sizeof(vis));
ans=0;
int tot=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d%d",&l[i],&r[i]);
m[tot++]=l[i];
m[tot++]=r[i];
}
sort(m,m+tot);
tot=unique(m,m+tot)-m;
//防止出现1 10,1 4,7 10这样的样例,所以才有下一步
for(int i=tot-1;i>=1;i--)
{
if(m[i]-m[i-1]>1)
m[tot++]=m[i-1]+1;
}
sort(m,m+tot);
for(int i=0;i<n;i++)
{
int ll=lower_bound(m,m+tot,l[i])-m;
int rr=lower_bound(m,m+tot,r[i])-m;
update(1,1,tot,ll+1,rr+1,i+1);
}
query(1,1,tot);
printf("%d\n",ans);
}
return 0;
}
/*****矩形并求总面积*****/
double x1,yy1,x2,y2;
double m[maxn];
struct node
{
double l,r,h;
int k;
} e[maxn];
int cmp(node x,node y)
{
return x.h<y.h;
}
struct nodee
{
int l,r,w;
double len;
} tree[maxn];
void build(int root,int l,int r)
{
tree[root].l=l,tree[root].r=r;
tree[root].len=0.0,tree[root].w=0;
if(l==r) return ;
int mid=(l+r)/2;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
}
void bac(int root)
{
int l=tree[root].l-1,r=tree[root].r;//r不减1把缺失的区间找回来
if(tree[root].w)
{
tree[root].len=m[r]-m[l];
}
else if(tree[root].l==tree[root].r)//注意
tree[root].len=0;
else
tree[root].len=tree[root<<1].len+tree[root<<1|1].len;
}
void update(int root,int ql,int qr,int x)
{
int l=tree[root].l,r=tree[root].r;
if(ql<=l&&r<=qr)
{
tree[root].w+=x;
bac(root);
return ;
}
int mid=(l+r)/2;
if(mid>=ql) update(root<<1,ql,qr,x);
if(mid<qr) update(root<<1|1,ql,qr,x);
bac(root);
}
int main()
{
int n;
int tt=1;
while(~scanf("%d",&n)&&n)
{
int tot=0;
for(int i=0; i<n; i++)
{
scanf("%lf%lf%lf%lf",&x1,&yy1,&x2,&y2);
e[tot].l=x1;
e[tot].r=x2;
e[tot].h=yy1;
e[tot].k=1;
m[tot++]=x1;
e[tot].l=x1;
e[tot].r=x2;
e[tot].h=y2;
e[tot].k=-1;
m[tot++]=x2;
}
sort(e,e+tot,cmp);
sort(m,m+tot);
tot=unique(m,m+tot)-m;
build(1,1,tot);
double ans=0.0;
for(int i=0; i<2*n-1; i++)
{
int ll=lower_bound(m,m+tot,e[i].l)-m;
int rr=lower_bound(m,m+tot,e[i].r)-m;
update(1,ll+1,rr,e[i].k);//rr不加1避免区间缺失
ans+=(e[i+1].h-e[i].h)*tree[1].len;
}
printf("Test case #%d\n",tt++);
printf("Total explored area: %.2lf\n\n",ans);
}
return 0;
}
/*****矩形并求叠加层数为2的*****/
double x1,yy1,x2,y2;
double m[maxn];
struct node
{
double l,r,h;
int k;
} e[maxn];
int cmp(node x,node y)
{
return x.h<y.h;
}
struct nodee
{
int l,r,w;
double len,lenn;
} tree[maxn];
void build(int root,int l,int r)
{
tree[root].l=l,tree[root].r=r;
tree[root].len=0.0;
tree[root].w=0;
tree[root].lenn=0.0;
if(l==r) return ;
int mid=(l+r)/2;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
}
void bac(int root)
{
int l=tree[root].l-1,r=tree[root].r;//r不减1把缺失的区间找回来
if(tree[root].w)
tree[root].len=m[r]-m[l];
else if(tree[root].l==tree[root].r)
tree[root].len=0;
else
tree[root].len=tree[root<<1].len+tree[root<<1|1].len;
if(tree[root].w>1)
tree[root].lenn=m[r]-m[l];
else if(tree[root].l==tree[root].r)
tree[root].lenn=0;
else if(tree[root].w==1)
tree[root].lenn=tree[root<<1].len+tree[root<<1|1].len;
else
tree[root].lenn=tree[root<<1].lenn+tree[root<<1|1].lenn;
}
void update(int root,int ql,int qr,int x)
{
int l=tree[root].l,r=tree[root].r;
if(ql<=l&&r<=qr)
{
tree[root].w+=x;
bac(root);
return ;
}
int mid=(l+r)/2;
if(mid>=ql) update(root<<1,ql,qr,x);
if(mid<qr) update(root<<1|1,ql,qr,x);
bac(root);
}
int main()
{
int t,n;
int tt=1;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(m,0,sizeof(m));
int tot=0;
for(int i=0; i<n; i++)
{
scanf("%lf%lf%lf%lf",&x1,&yy1,&x2,&y2);
e[tot].l=x1;
e[tot].r=x2;
e[tot].h=yy1;
e[tot].k=1;
m[tot++]=x1;
e[tot].l=x1;
e[tot].r=x2;
e[tot].h=y2;
e[tot].k=-1;
m[tot++]=x2;
}
sort(e,e+tot,cmp);
sort(m,m+tot);
tot=unique(m,m+tot)-m;
build(1,1,tot);
double ans=0.0;
for(int i=0; i<2*n-1; i++)
{
int ll=lower_bound(m,m+tot,e[i].l)-m;
int rr=lower_bound(m,m+tot,e[i].r)-m;
update(1,ll+1,rr,e[i].k);//rr不加1避免区间缺失
ans+=(e[i+1].h-e[i].h)*tree[1].lenn;
}
printf("%.2lf\n",ans);
}
return 0;
}