jzoj4419
GFS打算去郊外建所别墅,享受生活,于是他耗费巨资买下了一块风水宝地,但令他震惊的是,一群DSJ对GFS的富贵生活深恶痛绝,决定打洞以搞破坏。
现在我们简化一下这个问题,在这片土地上会按顺序发生一系列事件。
①一只DSJ在(x,y) 这个点打了一个洞。
②有着高雅品味GFS想建一个等腰直角三角形的别墅,即由(x,y) ,(x+d,y) ,(x,y+d) 三点围成的三角形,但为了地基的牢固,他想知道当前这块三角形土地内的洞的个数。
GFS现在对DSJ已经忍无可忍了,请你帮他回答这些询问。
初始土地上没有洞。GFS毕竟是GFS,你可以认为土地无限大。
這道題是四維偏序問題
我們考慮一下什麼時候一個洞(a,b)會對一次查詢(x,y,d)產生影響
則有x<=a<=x+d,y<=b<=y+d,x+y<=a+b<=x+y+d這三種條件
將(時間,a,b,a+b)看做平面上的一個點,這樣問題就轉換為了3維查詢
每一個查詢操作查詢空間內滿足x<=a<=x+d,y<=b<=y+d,a+b<=x+y+d的(a,b,a+b)
這個可以直接4維偏序
我們可以考慮將a+b這一維在cdq1中排序,因為a+b這一維沒有任何左邊界限制
這樣,我們就可以知道,我們在這一維cdq中將其排序過後,左右兩邊的a+b值都是有序的
我們再次遞歸下一層的cdq2,在cdq2中將區間[l,mid]和[mid+1,r]中的x值從小到大排序一遍
這樣子會將x值都排序一遍,a+b值會變亂
但是左邊的a+b值還是大於x值,所以還是可以使用左邊的更新右邊的值
這樣子還是3維偏序問題,要拆成4個詢問,會tle,需要優化
然而這道題中,我們因為已經在cdq1中將a+b排序了,所以我們可以保證,接下來序列中從左邊取出來的x值最小的修改操作,這個操作的x+y值會恆小於所有後來的查詢操作
所以,這個修改操作可以用來影響後面的查詢操作
由於a+b<=x+y+d這個條件,等價于a<=x+d且b<=y,也等價于b<=y+d 且a<=x,所以我們只需要查詢x<=a且y<=b的數對即可
這個數對怎麼求?
首先我們可以將x值排一遍序
將所有的左邊修改操作,右邊的查詢操作放進2個數組中
每次,掃描所有右邊的查詢操作,維護一個指針p,初始值為第二個數組的元素個數
當現在循環的查詢操作的x小於現在p指向的元素的x時,則現在p指向的元素可能會對現在的查詢操作有影響,所以可以將其y值加進樹狀數組,通過while不斷的添加,直到不滿足條件為止
然後,我們可以知道,在循環過後,所有數組內1-p的元素的x值都小於現在的x值,不可能對現在的答案產生任何影響
所以只有樹狀數組內的所有元素才會對現在的答案產生影響
但是,所有元素都不一定會對現在的答案產生影響
只有y值比現在詢問的值大的元素才會對現在的答案產生影響
所以,我們可以使用樹狀數組維護這個答案
這樣子,我們就成功的解決了本題
注意事項:必須將y+1,因為bits遇到y=0的情況下會死循環!!!!!!!!
cdq分治要寫成l>=r
代碼:
#include<bits/stdc++.h>
using namespace std;
struct no{
int a,b,c,p;
}q[100010],a[100010],b[100010],c[100010];
int n,x,y,d,t[10000000],mx,ct,v,ans[100010];
bool cp1(no x,no y){return x.c<y.c||x.c==y.c&&x.p<y.p;}
bool cp2(no x,no y){return x.a<y.a;}
void add(int x,int y){for(;x<=mx;x+=x&-x)t[x]+=y;v+=y;}
int qu(int x){int r=v;for(;x;x-=x&-x)r-=t[x];return r;}
void cdq2(int l,int r){
if(l>=r)return;
int c1=0,c2=0,mid=(l+r)/2;
cdq2(l,mid);cdq2(mid+1,r);
for(int i=l;i<=mid;i++)
if(!a[i].p)b[++c1]=a[i];
for(int i=mid+1;i<=r;i++)
if(a[i].p)c[++c2]=a[i];
sort(b+1,b+c1+1,cp2);sort(c+1,c+c2+1,cp2);
int p=c1+1;
for(int i=c2;i>=1;i--){
while(p>1&&b[p-1].a>=c[i].a){
p--;
add(b[p].b,1);
}
ans[c[i].p]+=qu(c[i].b-1);
}
for(int i=p;i<=c1;i++)
add(b[i].b,-1);
}
void cdq1(int l,int r){
if(l>=r)return;
int c1=0,mid=(l+r)/2;
cdq1(l,mid);cdq1(mid+1,r);
for(int i=l;i<=mid;i++)
if(!q[i].p)a[++c1]=q[i];
for(int i=mid+1;i<=r;i++)
if(q[i].p)a[++c1]=q[i];
sort(a+1,a+c1+1,cp1);
cdq2(1,c1);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&x,&y,&d);
q[i].a=x;q[i].b=y;q[i].c=x+y+d;
q[i].b++;
mx=max(mx,y+d);
if(d)q[i].p=++ct;
}
cdq1(1,n);
for(int i=1;i<=ct;i++)
printf("%d\n",ans[i]);
printf("\n");
}
jzoj4419的更多相关文章
随机推荐
- phpstorm2018.3的安装和激活和汉化
安装 第一步:解压并打开文件,运行安装程序,点击Next进入下一步, 第二步:选择软件安装目录,自定义选择安装根目录--> 注意!后面还需要找安装目录里的文件,所以记住安装到一个比较容易查看的目 ...
- c++ 对象复制引用时何时调用构造函数、析构函数
class TEST{ private : public : TEST() {std::cout << "constructor" << std::endl ...
- 构造函数constructor 与析构函数destructor(三)
(1)构造函数初始化列表: 1 class Test{ 2 int i; 3 public: 4 Test(int vi):i(vi){}//这里的从冒号开始,到右大括号结束,这一段是构造函数初始化列 ...
- 2018.09.01 poj2689 Prime Distance(埃式筛法)
传送门 一道挺有趣的. 第一眼以为每个数都用miller_rabin判一次,但感觉会被卡时间啊. 继续分析发现可以晒出sqrt(r)中的所有素数,然后用类似埃式筛法的方法晒出[l,r]" r ...
- 2018.08.27 lucky(模拟)
描述 Ly 喜欢幸运数字,众所周知,幸运数字就是数字位上只有 4 和 7 的数字. 但是本题的幸运序列和幸运数字完全没关系,就是一个非常非常普通的序列. 哈哈,是 不是感觉被耍了,没错,你就是被耍了. ...
- 【Unity】2.1 初识Unity编辑器
分类:Unity.C#.VS2015 创建日期:2016-03-26 一.简介 本节要点:了解Unity编辑器的菜单和视图界面,以及最基本的操作,这是入门的最基础部分,必须掌握. 二.启动界面 双击桌 ...
- sqlite3数据库,增删改查
搜索libsql //由于文件读写,归档,NSUserDefault,做持久存储的时候,是一个覆盖的过程,效率太低,更多的时候使用数据库来做持久化存储 //鉴于手机的硬件配置,使用轻量 ...
- Tensorflow从源代码编译2
https://blog.csdn.net/qq_37674858/article/details/81095101 https://blog.csdn.net/yhily2008/article/d ...
- VS 附加不上w3wp.exe
今天调用VS 附加不上w3wp.exe,其他的站点都能附加上,就有一个站附加不上,找了各种可能都没有解决,结果发现是版本被编译成release了,原来的配置都是debug的,不知道被谁给改成relea ...
- 【算法34】蓄水池抽样算法 (Reservoir Sampling Algorithm)
蓄水池抽样算法简介 蓄水池抽样算法随机算法的一种,用来从 N 个样本中随机选择 K 个样本,其中 N 非常大(以至于 N 个样本不能同时放入内存)或者 N 是一个未知数.其时间复杂度为 O(N),包含 ...