题解 P4515 【[COCI2009-2010#6] XOR】
xtx1092515503
2020-11-02 11:04:54
这里介绍一种复杂度更优(理论复杂度 $O(n^3\log n)$)的方法。
不知道大家有没有做过[这道题](https://www.luogu.com.cn/problem/P3219),它的做法就是在等腰直角三角形的场景下应用**扫描线**。我们在 $x$ 轴上做一条扫描线,并只求如下场景上的值:
1. 有一个三角形撞上了扫描线
2. 扫描线中某两个三角形不再相交
3. 有一个三角形离开了扫描线
其中(1)是很好处理的;(2)(3)可以合并处理,如下代码给出了求下一个特殊时刻的算法:
```cpp
int nex(){
int mn=0x3f3f3f3f;
for(int i=1;i<=m;i++)for(int j=1;j<=m;j++)if(p[j].second>p[i].first)mn=min(mn,p[j].second-p[i].first);
return mn;
}
```
求特殊时刻扫描线上的有效长度,可以通过 $O(n\log n)$ 将扫描线上东西离散化后,$O(n^2)$ 地暴力异或更新或者 $O(n)$ 地差分更新求得。这里为了方便直接暴力更新了。
此部分代码:
```cpp
int calc(){
v.clear();
for(int i=1;i<=m;i++)v.push_back(p[i].first),v.push_back(p[i].second);
sort(v.begin(),v.end()),v.resize(unique(v.begin(),v.end())-v.begin());
for(int i=0;i+1<v.size();i++)occ[i]=false;
for(int i=1;i<=m;i++){
int x=lower_bound(v.begin(),v.end(),p[i].first)-v.begin(),y=lower_bound(v.begin(),v.end(),p[i].second)-v.begin();
for(int j=x;j<y;j++)occ[j]^=1;
}
int ret=0;
for(int i=0;i+1<v.size();i++)if(occ[i])ret+=v[i+1]-v[i];
return ret;
}
```
两个特殊时刻间的面积,可以直接通过梯形面积公式求出。
时间复杂度 $O(n^3\log n)$,因为最多有 $O(n^2)$ 个特殊时间,每个特殊时间的有效长度需要 $O(n\log n)$ 地求出。
(所以明显本题可以被加强到 $n=100$,卡掉容斥的异端算法)
总代码:
```cpp
#include<bits/stdc++.h>
using namespace std;
int n,m;
struct node{
int x,y1,y2;
friend bool operator <(const node &u,const node &v){return u.x<v.x;}
}a[20];
pair<int,int>p[20];
vector<int>v;
bool occ[100];
int nex(){
int mn=0x3f3f3f3f;
for(int i=1;i<=m;i++)for(int j=1;j<=m;j++)if(p[j].second>p[i].first)mn=min(mn,p[j].second-p[i].first);
return mn;
}
int calc(){
v.clear();
for(int i=1;i<=m;i++)v.push_back(p[i].first),v.push_back(p[i].second);
sort(v.begin(),v.end()),v.resize(unique(v.begin(),v.end())-v.begin());
for(int i=0;i+1<v.size();i++)occ[i]=false;
for(int i=1;i<=m;i++){
int x=lower_bound(v.begin(),v.end(),p[i].first)-v.begin(),y=lower_bound(v.begin(),v.end(),p[i].second)-v.begin();
for(int j=x;j<y;j++)occ[j]^=1;
}
int ret=0;
for(int i=0;i+1<v.size();i++)if(occ[i])ret+=v[i+1]-v[i];
return ret;
}
void nex(int x){
for(int i=1;i<=m;i++)p[i].second-=x;
int len=0;
for(int i=1;i<=m;i++)if(p[i].first!=p[i].second)p[++len]=p[i];
m=len;
}
long long res;
int main(){
// freopen("I.in","r",stdin);
// freopen("A.out","w",stdout);
scanf("%d",&n);
for(int i=1,x,y,z;i<=n;i++)scanf("%d%d%d",&x,&y,&z),a[i].x=x,a[i].y1=y,a[i].y2=y+z;
sort(a+1,a+n+1);
for(int i=1,las=0,laslen=0;;){
if(!m&&i>n)break;
int delta=nex();
if(i<=n)delta=min(delta,a[i].x-las);
nex(delta);
int now=calc();
if(las!=0)res+=1ll*delta*(now+laslen),las+=delta;
else las=delta;
if(i<=n&&a[i].x<=las)p[++m]=make_pair(a[i].y1,a[i].y2),i++,laslen=calc();
else laslen=now;
}
printf("%lld.%d\n",res>>1,(res&1)?5:0);
return 0;
}
```