洛谷4475 巧克力王国(KD-Tree + 维护子树和)
(嘤嘤嘤 又是一个自闭了一晚上的题)
qwq果然不是平面上的点的问题,也可以直接用KDTree打暴力
我们对于巧克力直接建kdtree
维护一个\(mx[i],mn[i]\)
但是有一个非常不友好的事情
我们貌似很难对这个东西进行一些实质上的剪枝
因为他求的是一个和的形式,而不是一个最值QWQ
那么该怎么办呢?
我们这时候考虑,对于一个kdtree上的每一个节点,我们都维护一个子树sum表示子树内的所有巧克力的权值之和。
那么对于一次\(query\),假设我们最大的甜度都不会超过\(c\)的话,那就代表我们可以直接把这个子树的\(sum\)加进\(ans\)里面了,因为他是一定能合法的
int getsum(cho a,peo b)
{
if (!a.num) return 1e9;
int tmp =0;
for (int i=0;i<=1;i++)
tmp=tmp+a.d[i]*b.d[i];
return tmp;
}
int calc(cho a,peo b)
{
if (!a.num) return 1e9;
int tmp =0;
for (int i=0;i<=1;i++)
tmp=tmp+min(a.mn[i]*b.d[i],a.mx[i]*b.d[i]);
return tmp;
}
int getmax(cho a,peo b)
{
if (!a.num) return 1e9;
int tmp = 0;
for (int i=0;i<=1;i++)
tmp=tmp+max(a.mx[i]*b.d[i],a.mn[i]*b.d[i]);
return tmp;
}
void query(int x)
{
if (!x) return;
if (getmax(t[x],now)<now.c)
{
tmp=tmp+t[x].sum;
return;
}
int c = now.c;
int d1 = calc(t[t[x].l],now);
int d2 = calc(t[t[x].r],now);
int d = getsum(t[x],now);
if (d<now.c) tmp=tmp+t[x].val;
if (d1<c) query(t[x].l);
if (d2<c) query(t[x].r);
}
那么其实剩下的问题也就迎刃而解了
直接上代码吧
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk makr_pair
#define ll long long
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 3e6+1e2;
struct cho{
int mn[2],mx[2];
int d[2];
int l,r;
int val;
int sum;
int num;
};
struct peo{
int d[2],c;
};
cho t[maxn];
peo now;
int n,m,root;
int sum;
int ymh;
int tmp;
bool operator < (cho a,cho b)
{
return a.d[ymh]<b.d[ymh];
}
void up(int root)
{
for (int i=0;i<=1;i++)
{
if (t[root].l)
{
t[root].mn[i]=min(t[root].mn[i],t[t[root].l].mn[i]);
t[root].mx[i]=max(t[root].mx[i],t[t[root].l].mx[i]);
}
if (t[root].r)
{
t[root].mn[i]=min(t[root].mn[i],t[t[root].r].mn[i]);
t[root].mx[i]=max(t[root].mx[i],t[t[root].r].mx[i]);
}
}
t[root].sum=t[root].val+t[t[root].l].sum+t[t[root].r].sum;
}
void build(int &x,int l,int r,int dd)
{
//cout<<1<<endl;
ymh = dd;
int mid = l+r >> 1;
x = mid;
nth_element(t+l,t+x,t+r+1);
for (int i=0;i<=1;i++) t[x].mn[i]=t[x].mx[i]=t[x].d[i];
if (l<x) build(t[x].l,l,mid-1,dd^1);
if (r>x) build(t[x].r,mid+1,r,dd^1);
up(x);
}
int getsum(cho a,peo b)
{
if (!a.num) return 1e9;
int tmp =0;
for (int i=0;i<=1;i++)
tmp=tmp+a.d[i]*b.d[i];
return tmp;
}
int calc(cho a,peo b)
{
if (!a.num) return 1e9;
int tmp =0;
for (int i=0;i<=1;i++)
tmp=tmp+min(a.mn[i]*b.d[i],a.mx[i]*b.d[i]);
return tmp;
}
int getmax(cho a,peo b)
{
if (!a.num) return 1e9;
int tmp = 0;
for (int i=0;i<=1;i++)
tmp=tmp+max(a.mx[i]*b.d[i],a.mn[i]*b.d[i]);
return tmp;
}
void query(int x)
{
if (!x) return;
if (getmax(t[x],now)<now.c)
{
tmp=tmp+t[x].sum;
return;
}
int c = now.c;
int d1 = calc(t[t[x].l],now);
int d2 = calc(t[t[x].r],now);
int d = getsum(t[x],now);
if (d<now.c) tmp=tmp+t[x].val;
if (d1<c) query(t[x].l);
if (d2<c) query(t[x].r);
}
signed main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
n=read(),m=read();
for (int i=1;i<=n;i++)
{
for(int j=0;j<=1;j++) t[i].d[j]=read();
t[i].val=read();
t[i].num=i;
}
build(root,1,n,0);
for(int i=1;i<=m;i++){
now.d[0]=read();
now.d[1]=read();
now.c=read();
tmp=0;
query(root);
cout<<tmp<<"\n";
}
return 0;
}
不过总的来说
kdtree真的是一个很优雅的暴力啊!
嘤嘤嘤