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 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”