zoukankan      html  css  js  c++  java
  • SHOI2013 扇形面积并

    传送门

    模拟题……然后被魔改成了小乔放技能……

    考试的时候一开始想二维差分,TLE+MLE,想扫描线,没法确定是否被覆盖K次,之后想一维差分,以为能过,后来发现因为有可能并不是相邻大小的半径覆盖一个区间,所以对半径排序是不好使的的。

    但其实这样真的行,我们只要用平衡树维护一下即可(顺便还得启发式合并)。

    但是改变一下思路。我们通过推一波式子能明白,其实扇形啥的没什么用,我们把给定的s,t作为横轴坐标,其实一个点的贡献值就是覆盖在这个点上第k大半径的平方。

    把点推广到区间也是一样,所以我们其实就可以把添加一个扇形改为添加一条半径和减少一条半径。这样的话,我们首先对所有扇形起始点拍一个序,之后这个区间对答案的贡献,就是两次端点的差值*第k大半径的平方。

    其中第k大半径可以用权值线段树进行维护。

    之后我们就愉快的做完啦!注意如果出现s > t的情况,需要拆分成两个区间进行维护。

    看一下代码。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<set>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define pb push_back
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 1000005;
    
    ll read()
    {
       ll ans = 0,op = 1;
       char ch = getchar();
       while(ch < '0' || ch > '9')
       {
          if(ch == '-') op = -1;
          ch = getchar();
       }
       while(ch >= '0' && ch <= '9')
       {
          ans *= 10;
          ans += ch - '0';
          ch = getchar();
       }
       return ans * op;
    }
    
    struct mis
    {
       ll r,s,val;
       bool operator < (const mis &g) const
       {
          return s < g.s;
       }
    }a[M];
    
    ll n,m,k,sum[M<<2],x,y,z,tot,ans,la,now;
    
    ll query(ll p,ll l,ll r,ll pos)
    {
       if(l == r) return l;
       ll mid = (l+r) >> 1;
       if(pos <= sum[p<<1]) return query(p<<1,l,mid,pos);
       else return query(p<<1|1,mid+1,r,pos - sum[p<<1]);
    }
    
    void modify(ll p,ll l,ll r,ll pos,ll val)
    {
       if(l == r)
       {
          sum[p] += val;
          return;
       }
       ll mid = (l+r) >> 1;
       if(pos <= mid) modify(p<<1,l,mid,pos,val);
       else modify(p<<1|1,mid+1,r,pos,val);
       sum[p] = sum[p<<1] + sum[p<<1|1];
    }
    
    int main()
    {
       n = read(),m = read(),k = read();
       rep(i,1,n)
       {
          x = read(),y = read(),z = read();
          if(y > z)
          {
         a[++tot].r = x,a[tot].s = -m,a[tot].val = 1;
         a[++tot].r = x,a[tot].s = z,a[tot].val = -1;
         a[++tot].r = x,a[tot].s = y,a[tot].val = 1;
         a[++tot].r = x,a[tot].s = m,a[tot].val = -1;
          }
          else
          {
         a[++tot].r = x,a[tot].s = y,a[tot].val = 1;
         a[++tot].r = x,a[tot].s = z,a[tot].val = -1;
          }
       }
       sort(a+1,a+1+tot);
       rep(i,1,tot)
       {
          ll d = query(1,0,100001,now-k+1);
          ans += d * d * (a[i].s - la);
          modify(1,0,100001,a[i].r,a[i].val);
          now += a[i].val,la = a[i].s;
       }
       printf("%lld
    ",ans);
       return 0;
    }
  • 相关阅读:
    Oracle中job的使用详解
    Control File (二)重建CONTROLFILE --- NORESETLOG
    Oracle Analyze 命令 详解
    深入学习Oracle分区表及分区索引
    B树索引和位图索引的区别!
    RAID0_RAID1_RAID10_RAID5各需几块盘才可组建
    Oracle IO优化心得
    修改dbwr后台进程数量
    查看ORACLE执行计划的几种常用方法
    printf()格式化输出详解及echo带颜色输出
  • 原文地址:https://www.cnblogs.com/captain1/p/9930681.html
Copyright © 2011-2022 走看看