Scx117
只一眼,便辽阔了时间。

题意:一共有n个盒子,每个盒子中有ai个气球。共进行q轮操作,在x盒子中踩烂一个气球,并询问有多少的小朋友是高兴的?

高兴:一共有m个小孩子,每个小孩子的区间为[li,ri],当这个区间盒子中的所有气球都被踩烂他就高兴。

n<=1e5。

 

标程:

 1 #include<cstdio>
 2 #define mid ((l+r)>>1)
 3 using namespace std;
 4 typedef long long ll;
 5 int read()
 6 {
 7     int x=0;char ch=getchar();
 8     while (ch<'0'||ch>'9') ch=getchar();
 9     while ('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=getchar();
10     return x;
11 }
12 const int N=100005;
13 int seg[N],head[N<<2],cnt,n,m,q,l,r,x,ans;//注意head是线段树上的点连边,大小开4倍! 
14 ll sum[N<<2];//注意气球总数很多,要开ll! 
15 struct node{int to,next;}num[N*30];
16 void add(int x,int y)
17 {num[++cnt].to=y;num[cnt].next=head[x];head[x]=cnt;}
18 void build(int k,int l,int r)
19 {
20     if (l==r) {sum[k]=read();return;}
21     build(k<<1,l,mid);build(k<<1|1,mid+1,r);
22     sum[k]=sum[k<<1]+sum[k<<1|1];
23 }
24 void ins(int k,int l,int r,int L,int R,int x)
25 {
26     if (L<=l&&r<=R) {add(k,x);seg[x]++;return;}
27     if (L<=mid) ins(k<<1,l,mid,L,R,x);
28     if (R>mid) ins(k<<1|1,mid+1,r,L,R,x);
29 }
30 void work(int x)
31 {
32    for (int i=head[x];i;i=num[i].next)
33      if (!--seg[num[i].to]) ans++;
34 }
35 void modi(int k,int l,int r,int x)
36 {
37     sum[k]--;if (!sum[k]) work(k);
38     if (l==r) return;
39     if (x<=mid) modi(k<<1,l,mid,x);
40       else modi(k<<1|1,mid+1,r,x);
41 }
42 int main()
43 {
44     n=read();m=read();build(1,1,n);
45     for (int i=1;i<=m;i++) l=read(),r=read(),ins(1,1,n,l,r,i);
46     q=read();
47     while (q--)
48     {
49        x=(read()+ans-1)%n+1;
50        modi(1,1,n,x); printf("%d\n",ans);
51     }
52     return 0;
53 }

 

题解:线段树优化建边

线段树维护的是气球盒子的区间。

每个小孩有一段区间,我们将这一段区间拆分成logn个对相应线段树上的区间连边。当这logn个区间的sum都为0时,他高兴。

对于一个踩气球的操作,相当于是单点修改-1。如果一段区间的sum=0,那么就把依赖它的小孩的seg(仍存在的依赖区间数)-1,如果某小孩的seg=0,那么ans++。

时间复杂度O((n+q)logn)。

posted on 2018-04-24 21:15  Scx117  阅读(166)  评论(0编辑  收藏  举报