zoukankan      html  css  js  c++  java
  • 洛谷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真的是一个很优雅的暴力啊!

    嘤嘤嘤

  • 相关阅读:
    JS中检测数据类型的方式
    DOM库
    原型应用(将数组去重写到数组的原型上)
    JS学习之原型和原型链模式
    JS学习之闭包、this关键字、预解释、作用域综合
    JS学习之作用域
    JS学习之预解释
    maven gradle 混合使用的问题
    libgdx 开发环境搭建
    maven 安装 jar
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10161962.html
Copyright © 2011-2022 走看看