洛谷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<<"
";
  }
  return 0;
}

不过总的来说

kdtree真的是一个很优雅的暴力啊!

嘤嘤嘤

原文地址:https://www.cnblogs.com/yimmortal/p/10161962.html