Gym101350 FMonkeying Around
题意
有n只猴子排成一排,一共有m个笑话。开始时,这些猴子都坐在椅子上。下面m行给出的每个笑话包含三个整数x,l,k。代表猴子x讲了笑话l,所以距离x小于等于k的猴子如果他们从没听过这个笑话,他们会掉下椅子,如果听过这个笑话他们会爬回椅子上。问在讲完m个笑话以后,还有哪些猴子是还坐在椅子上的。
分析
当时在场上想到了是线段树,但是总是想保存下每个猴子听每个笑话听了几遍,发现数组都开不下,很难受。。
我们来看大佬们的想法:
对于每只猴子,它是在椅子上还是在地上只取决于它听到的最后一个笑话一共听了几遍。
所以我们首先要找出每只猴子听到的最后一个笑话是什么,然后再找出这个笑话他听了几遍。
我们可以想到用两颗线段树分别求这两个东西。第一颗线段树是比较好想的,关键是第二颗。
假设我们现在已经知道了每只猴子听到的最后一个笑话是什么。
对于每个笑话,我们在一颗线段树上做,做完以后删除。然后统计最后一个听到的笑话是这个的人的听的次数。这样遍历笑话和猴子,均摊是O(n)的,线段树的操作是logn(这段话来自大佬:https://www.cnblogs.com/huibixiaoxing/p/7678842.html,感谢指点)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <vector> 6 7 using namespace std; 8 const int maxn=100000+10; 9 int T,n,m; 10 struct Node{ 11 int l,r,num; 12 }node[maxn]; 13 int x,l,k; 14 int set[4*maxn],num[maxn]; 15 void pushdown(int o){ 16 if(set[o]){ 17 set[2*o]=set[o]; 18 set[2*o+1]=set[o]; 19 set[o]=0; 20 } 21 } 22 int ql,qr,c; 23 void update(int o,int L,int R){ 24 if(ql<=L&&qr>=R){ 25 set[o]=c; 26 return; 27 } 28 pushdown(o); 29 int M=L+(R-L)/2; 30 if(ql<=M) 31 update(2*o,L,M); 32 if(qr>M) 33 update(2*o+1,M+1,R); 34 return ; 35 } 36 int ask(int o,int L,int R,int p){ 37 if(L==R){ 38 return set[o]; 39 } 40 pushdown(o); 41 int M=L+(R-L)/2; 42 if(p<=M) 43 return ask(2*o,L,M,p); 44 else 45 return ask(2*o+1,M+1,R,p); 46 } 47 //*******以下是第二棵线段树 48 int sum[4*maxn],addv[4*maxn]; 49 void pushdown2(int o){ 50 if(addv[o]){ 51 addv[2*o]+=addv[o];addv[2*o+1]+=addv[o]; 52 sum[2*o]+=addv[o];sum[2*o+1]+=addv[o]; 53 addv[o]=0; 54 } 55 return ; 56 } 57 58 void update2(int o,int L,int R){ 59 if(ql<=L&&qr>=R){ 60 addv[o]+=c; 61 sum[o]+=c; 62 return ; 63 } 64 pushdown2(o); 65 int M=L+(R-L)/2; 66 if(ql<=M) 67 update2(2*o,L,M); 68 if(qr>M) 69 update2(2*o+1,M+1,R); 70 return; 71 } 72 int ask2(int o,int L,int R,int p){ 73 if(L==R)return sum[o]; 74 int M=L+(R-L)/2; 75 pushdown2(o); 76 if(p<=M) 77 return ask2(2*o,L,M,p); 78 else 79 return ask2(2*o+1,M+1,R,p); 80 } 81 struct Interval{ 82 int l,r; 83 }; 84 vector<Interval>V1[maxn]; 85 vector<int>V2[maxn]; 86 int M,ans; 87 int main(){ 88 scanf("%d",&T); 89 for(int t=1;t<=T;t++){ 90 M=-1,ans=0; 91 scanf("%d%d",&n,&m); 92 for(int i=0;i<maxn;i++)V1[i].clear(); 93 for(int i=0;i<maxn;i++)V2[i].clear(); 94 95 memset(set,0,sizeof(set)); 96 for(int i=1;i<=m;i++){ 97 scanf("%d%d%d",&x,&l,&k); 98 node[i].l=max(1,x-k); 99 node[i].r=min(n,x+k); 100 node[i].num=l; 101 M=max(M,node[i].num); 102 V1[node[i].num].push_back((Interval){node[i].l,node[i].r}); 103 ql=node[i].l,qr=node[i].r,c=node[i].num; 104 update(1,1,n); 105 } 106 for(int i=1;i<=n;i++){ 107 int g=ask(1,1,n,i); 108 // cout<<i<<" "<<g<<endl; 109 V2[g].push_back(i); 110 } 111 112 memset(sum,0,sizeof(sum)); 113 memset(addv,0,sizeof(addv)); 114 /* for(int i=1;i<=M;i++){ 115 printf("%d :",i); 116 for(int j=0;j<V2[i].size();j++){ 117 printf("%d ",V2[i][j]); 118 } 119 printf("\n"); 120 }*/ 121 for(int i=1;i<=M;i++){ 122 // cout<<i<<endl; 123 for(int j=0;j<V1[i].size();j++){ 124 Interval inter=V1[i][j]; 125 ql=inter.l,qr=inter.r,c=1; 126 update2(1,1,n); 127 } 128 for(int j=0;j<V2[i].size();j++){ 129 if(ask2(1,1,n,V2[i][j])>=2){ 130 // printf("%d %d\n",V2[i][j],ask2(1,1,n,V2[i][j])); 131 ans++; 132 } 133 } 134 for(int j=0;j<V1[i].size();j++){ 135 Interval inter=V1[i][j]; 136 ql=inter.l,qr=inter.r,c=-1; 137 update2(1,1,n); 138 } 139 } 140 printf("%d\n",ans); 141 }; 142 return 0;