天神下凡题解
题目描述 Czy找到宝藏获得屠龙宝刀和神秘秘籍!现在他要去找经常ntr他的Jmars报仇…… Czy学会了一招“堕天一击”,他对一个地点发动堕天一击,地面上就会留下一个很大的圆坑。圆坑的周围一圈能量太过庞大,因此无法通过。所以每次czy发动技能都会把地面分割。Jmars拥有好大好大的土地,几十眼都望不到头,所以可以假设土地的大小是无限大。现在czy对他发动了猛烈的攻击,他想知道在泽宇攻击之后他的土地被切成几份了? Czy毕竟很虚,因此圆心都在x坐标轴上。另外,保证所有圆两两之间不会相交。 输入 输入第一行为整数n,表示czy放了n次堕天一击。 接下来n行,每行两个整数x[i],r[i]。表示在坐标(x[i] , 0)放了一次堕天一击,半径为r[i]。 输出 输出一行,表示地面被分割成几块。 样例输入 4 7 5 -9 11 11 9 0 20 样例输出 6
考试的时候打了n^2的dp,只拿到了30分部分分。
一个解法:
扫描线(其实打完了发现也就是暴力模拟),先按左端点小的排序,如果左端点相同则右端点大的在前,这样可以保证每个小圆被大圆包含,本身每个圆对答案贡献是1,但是有可能一个大圆被许多小圆分割成两部份,对答案贡献需要加1,所以O(n)枚举排序后的每个圆,如果当前圆左边界和下一个圆左边界相同则说明这个圆可以被分割(但这时要注意倒数第二个圆),将这个圆压入栈。如果这个圆的右端点和栈顶圆的右端点相同则说明栈顶的大圆可以被分割,对答案贡献加1,。如果这个圆的右端点和下一个圆的左端点没有相连,则栈顶的大圆无法被彻底分割,出栈。
最后的num为被彻底分割大圆做出的贡献,本身每个圆都对答案有1个贡献,且所有圆外面也是一部份,所以最终答案应为num+n+1
好像大神的解法是线段树,不过蒟蒻太弱了,没有想出来,就打了个暴力模拟QAQ,膜大佬Orzzzz
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 using namespace std; 7 __attribute__((optimize("O3")))int read() { 8 int s=0,f=1; 9 char ch=getchar(); 10 while(ch>'9'||ch<'0') { 11 if(ch=='-') 12 f=-1; 13 ch=getchar(); 14 } 15 while(ch>='0'&&ch<='9') { 16 s=(s<<1)+(s<<3)+(ch^48); 17 ch=getchar(); 18 } 19 return s*f; 20 } 21 struct oo { 22 int l,r; 23 } cir[300005]; 24 int n; 25 __attribute__((optimize("O3")))bool cmp(oo a,oo b) { 26 if(a.l<b.l) { 27 return 1; 28 } 29 if(a.l>b.l) { 30 return 0; 31 } 32 if(a.r>b.r) { 33 return 1; 34 } 35 return 0; 36 } 37 int stack[300005],tail; 38 __attribute__((optimize("O3")))int main() { 39 //freopen("god8.in","r",stdin); 40 n=read(); 41 for(int i=1; i<=n; i++) { 42 int x=read(),r=read(); 43 cir[i].l=x-r; 44 cir[i].r=x+r; 45 } 46 sort(cir+1,cir+1+n,cmp); 47 int ans=0; 48 for(int i=1; i<=n; i++) { 49 if(cir[i].l==cir[i+1].l&&i+1!=n) { 50 stack[++tail]=i; 51 continue; 52 } 53 if(cir[i].r==cir[stack[tail]].r) { 54 ans++; 55 tail--; 56 } 57 if(cir[i].r!=cir[i+1].l) { 58 if(tail) { 59 tail--; 60 } 61 } 62 } 63 printf("%d\n",n+ans+1); 64 return 0; 65 }