bzoj2527 [Poi2011]Meteors

这个题是在GYZ冬令营讲课课件里翻出来的,所以我一开始使劲地往分治上去想,良久,无果··········

题意是给你一圈位置,位置上有若干颜色(可以重复),每个颜色有一个需求量,每一个时间给一个段加上一个数,最后问每个颜色最早加到需求量的时间。

今天早晨睡觉起来(大概是10点多),赖在床上,YY这个题,突然想到整体二分然后计算贡献似乎非常不错。但是对于序列的处理怎么搞才能把复杂度降下来呢?于是我想到用链表记录每个颜色的位置,这样计算均摊下来就是O(m)了,用树状数组处理,外面套一个整体二分,似乎是非常不错。(但我不知道这算不算与序列长度线性相关了,XHR论文里不是说必须跟询问长线性相关吗?)

整理一下思路,我们二分答案(修改操作的标号),对于[L,R]这一次分治,我们令[L,MID]这些修改操作生效,然后计算每一个询问(1..n个位置),如果求得各个位置的和大于需求,那么将这个询问划分到左区间,否则将各个位置的和累加到贡献上,将询问划分到右区间,整体二分的思路,一气呵成!

对于NIE情况的处理,可以在最后加一个给所有数加上1e9+1,这样如果计算到的答案是Q+1的话输出NIE。

 

meteors
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<cstring>
  6 #define maxn 301000
  7 #define inf 100000000000ll
  8 using namespace std;
  9 struct query
 10 {
 11     int pos;
 12     long long cur,ned;
 13 }q[maxn],q1[maxn],q2[maxn];
 14 struct adj
 15 {
 16     int l,r;
 17     long long s;
 18 }c[maxn];
 19 int ans[maxn],fir[maxn],last[maxn],next[maxn];
 20 int n,m,p;
 21 struct bit
 22 {
 23     long long b[maxn];
 24     void add(int x,long long z)
 25     {
 26         for (int i=x;i<=m;i+=(i&-i)) b[i]+=z;
 27     }
 28     long long ask(int x)
 29     {
 30         long long tmp=0;
 31         for (int i=x;i;i-=(i&-i)) tmp+=b[i];
 32         return tmp;
 33     }
 34 }s;
 35 
 36 void adjust(int l,int r,long long z)
 37 {
 38     s.add(l,z); s.add(r+1,-z);
 39 }
 40 
 41 long long query(int x)
 42 {
 43     return s.ask(x);
 44 }
 45 
 46 void solve(int l,int r,int head,int tail)
 47 {
 48     if (head>tail) return ;
 49     if (l==r)
 50     {
 51         for (int i=head;i<=tail;i++)
 52             ans[q[i].pos]=l;
 53         return ;
 54     }
 55     int mid=(l+r)/2,t1=0,t2=0;
 56     for (int i=l;i<=mid;i++)
 57         if (c[i].l<=c[i].r) adjust(c[i].l,c[i].r,c[i].s);
 58         else adjust(c[i].l,m,c[i].s),adjust(1,c[i].r,c[i].s);
 59     for (int i=head;i<=tail;i++)
 60     {
 61         long long tmp=0;
 62         for (int j=fir[q[i].pos];j&&tmp<=inf;j=next[j])
 63             tmp+=query(j);
 64         if (q[i].cur+tmp>=q[i].ned)
 65             q1[++t1]=q[i];
 66         else
 67         {
 68             q[i].cur+=tmp;
 69             q2[++t2]=q[i];
 70         }
 71     }
 72     for (int i=l;i<=mid;i++)
 73         if (c[i].l<=c[i].r) adjust(c[i].l,c[i].r,-c[i].s);
 74         else adjust(c[i].l,m,-c[i].s),adjust(1,c[i].r,-c[i].s);
 75     for (int i=1;i<=t1;i++) q[head+i-1]=q1[i];
 76     for (int i=1;i<=t2;i++) q[head+t1+i-1]=q2[i];
 77     solve(l,mid,head,head+t1-1);
 78     solve(mid+1,r,head+t1,tail);
 79 }    
 80 
 81 int main()
 82 {
 83     //freopen("meteors.in","r",stdin);
 84     scanf("%d%d",&n,&m);
 85     int a;
 86     for (int i=1;i<=m;i++)
 87     {
 88         scanf("%d",&a);
 89         if (!fir[a]) fir[a]=i;
 90         next[last[a]]=i;
 91         last[a]=i;
 92     }
 93     for (int i=1;i<=n;i++) 
 94     {
 95         scanf("%d",&q[i].ned);
 96         q[i].pos=i; q[i].cur=0;
 97     }
 98     scanf("%d",&p);
 99     for (int i=1;i<=p;i++)
100         scanf("%d%d%d",&c[i].l,&c[i].r,&c[i].s);
101     c[++p].l=1; c[p].r=m; c[p].s=1000000010;
102     solve(1,p,1,n);
103     for (int i=1;i<=n;i++)
104         if (ans[i]==p) printf("NIE\n");
105         else printf("%d\n",ans[i]);
106     return 0;
107 }

 

转载于:https://www.cnblogs.com/zig-zag/archive/2013/04/29/3051212.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值