BZOJ3932 任务查询系统

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3932

知识点:  可持久化线段树、差分数组

解题思路:

  将每一个任务转化成差分数组,即

\((S, E, C) \rightarrow Differential[S] = C, Differential[E+1] = -C\).

  然后以差分数组的顺序将每一个任务更新进可持久化线段树中。其他的就都是套路了。几个小细节可以参考一下代码和注释。

  其实,可持久化线段树中除了最开始建的那一棵空树外的线段树都是在上一棵线段树的基础上更新出来的,所以在做相关的题目的时候一定要注意找出其中隐藏的顺序。可持久化树成立的基础是有序性!(拙见)

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 100000+5;
 5 
 6 struct Upd{
 7     ll flag,you;
 8     int t;
 9 }ud[maxn<<1];
10 bool cmp(const Upd &a,const Upd &b){
11     return a.t<b.t;
12 }
13 int times[maxn<<1];
14 ll Yo[maxn];
15 int lson[maxn<<7],rson[maxn<<7],T[maxn<<7]; 
16 ll sum[maxn<<7],siz[maxn<<7];
17 int tot=0;
18 void build(int l,int r,int &rt){
19     rt=++tot;
20     sum[rt]=siz[rt]=0;
21     if(l==r)    return ;
22     int m=(l+r)>>1;
23     build(l,m,lson[rt]);    build(m+1,r,rson[rt]);
24 }
25 void update(int last,ll iyou,ll iflag,int l,int r,int &rt){
26     rt=++tot;
27     lson[rt]=lson[last];
28     rson[rt]=rson[last];
29     sum[rt]=sum[last]+iflag*iyou;
30     siz[rt]=siz[last]+iflag;
31     if(l==r)    return;
32     int m=(l+r)>>1;
33     if(Yo[m]>=iyou) update(lson[last],iyou,iflag,l,m,lson[rt]);
34     else        update(rson[last],iyou,iflag,m+1,r,rson[rt]);
35 }
36 ll query(int pt,ll k,int l,int r){
37     if(l==r)    return min(k,siz[pt])*sum[pt]/siz[pt];  //这个点的所有优先级未必能全取
38     int m=(l+r)>>1;
39     if(siz[pt]<=k)  return sum[pt];
40     if(siz[lson[pt]]<k)
41         return sum[lson[pt]]+query(rson[pt],k-siz[lson[pt]],m+1,r);
42     if(0<k)
43         return query(lson[pt],k,l,m);
44     return 0;
45 }
46 int to[maxn];
47 int main(){
48     int m,n,S,E;
49     ll C;
50     scanf("%d%d",&m,&n);
51     int cnt=0,cnty=1;
52     for(int i=1;i<=m;i++){
53         scanf("%d%d%lld",&S,&E,&C);
54         Yo[cnty++]=C;
55         ud[cnt].flag=1,ud[cnt].you=C,ud[cnt].t=S;
56         times[cnt]=S;
57         cnt++;
58         ud[cnt].flag=-1,ud[cnt].you=C,ud[cnt].t=E+1;
59         times[cnt]=E+1;
60         cnt++;
61     }
62     sort(ud,ud+cnt,cmp);    //差分数组排序
63     
64     times[cnt++]=0;
65     sort(times,times+cnt);
66     int mt=unique(times,times+cnt)-times;   //时间离散化
67     
68     sort(Yo+1,Yo+1+cnty);   
69     int my=unique(Yo+1,Yo+1+cnty)-Yo-1; //优先级离散化
70 
71     build(1,my,T[0]);   //建空树
72     to[0]=0;
73     int now=0;
74     for(int i=0;i<m*2;i++){
75         update(T[i],ud[i].you,ud[i].flag,1,my,T[i+1]);
76         while(times[now]!=ud[i].t&&now<mt)   now++;
77         to[now]=i+1;    //to[]指出times[]数组中的下标对应的可持久化线段树的根
78     }
79     ll pre=1,a,b,c;
80     int x;
81     for(int i=0;i<n;i++){
82         scanf("%d%lld%lld%lld",&x,&a,&b,&c);
83         ll k=1+(a*pre+b)%c;
84         int pt=upper_bound(times,times+mt,x)-times-1;
85         pre=query(T[to[pt]],k,1,my);
86         printf("%lld\n",pre);
87     }
88 
89     return 0;
90 }

 

posted @ 2018-02-07 02:45  Blogggggg  阅读(208)  评论(0编辑  收藏  举报