1. 程式人生 > >JZOJ-senior-5960. 【NOIP2018模擬11.8A組】小喬

JZOJ-senior-5960. 【NOIP2018模擬11.8A組】小喬

Time Limits: 1000 ms Memory Limits: 524288 KB

Description

在這裡插入圖片描述 在這裡插入圖片描述

Input

在這裡插入圖片描述

Output

在這裡插入圖片描述

Sample Input

3 8 2 1 -8 8 3 -7 3 5 -5 5

Sample Output

76 在這裡插入圖片描述

Data Constraint

在這裡插入圖片描述 在這裡插入圖片描述

Solution

很顯然,這個圖形可以被我們以某條線割開,拉出來變成一個線段上的問題,注意 s>ts>t 的情況 這就變成了平面圖上的矩形覆蓋問題,問覆蓋次數不少於 kk 次的面積 矩形覆蓋必須從最底往上,那下方覆蓋的次數會比上方多,符合二分的性質 我們採用掃描線,對於左端,把它加入樹狀陣列,右端,則刪去左端標記 採用樹狀陣列,對於每個位置,找出覆蓋它次數剛好為 k

k 的最外端並統計答案

Code

#include<algorithm>
#include<cstdio>

#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#define ll long long

using namespace std;

const int N=5e5+5,R=5e5+5,inf=1e9;
int n,m,k,cnt,c[R+5];
struct node{int x,r,k;}a[2*N];

bool cmp(node x,
node y) { return x.x<y.x||x.x==y.x&&x.k>y.k; } void ins(int x,int y) { while(x<=R) c[x]+=y,x+=x&(-x); } int sum(int x) { if(!x) return inf; int s=0; while(x) s+=c[x],x-=x&(-x); return s; } int find() { int l=0,r=R+1,out=0; while(l<=r) { int mid=(l+r)>>1; if
(sum(mid)>=k) out=max(out,mid),l=mid+1; else r=mid-1; } return out; } int main() { freopen("xiaoqiao.in","r",stdin); freopen("xiaoqiao.out","w",stdout); scanf("%d%d%d",&n,&m,&k); fo(i,1,n) { int r,s,t; scanf("%d%d%d",&r,&s,&t); if(s<t) { a[++cnt]=(node){s,r,1}; a[++cnt]=(node){t,r,-1}; } if(s>t) { a[++cnt]=(node){s,r,1}; a[++cnt]=(node){m,r,-1}; a[++cnt]=(node){-m,r,1}; a[++cnt]=(node){t,r,-1}; } } sort(a+1,a+1+cnt,cmp); int i=1; ll ans=0; fo(line,-m,m) { int r=find(); if(r<=R) ans=ans+(ll)r*r; while(i<=cnt&&a[i].x<=line) { if(a[i].k>0) ins(1,1),ins(a[i].r+1,-1); else ins(1,-1),ins(a[i].r+1,1); ++i; } } printf("%lld",ans); }