对于昨天的考试,可以说是把暴力分都拿到了
T1 的搜索方式还是根据了这道题的性质,就是总的步数很少,然后再贪心的由小往大的更新,这样时间效率几乎就是O(N)的;想要做出来这道题,首先就是要分析出来
往回走的步数其实是非常少的,至于如何分析出来,就可以直接打一个暴力,用一些时间搞出一些大数据的答案,然后再结合一下倍增的性质,应该就可以分析出来,然后就是如何去搜索,再搜索的时候,往往是和贪心减枝有紧密联系的,对于这道题,就是用小的步数去尽可能的更新多的点,然后之后枚举的步数就只用关注未确定步数的点
T2的话,是一个莫比乌斯反演,其实这道题的暴力的极限应该是40分,但是当时还是不太懂μ做容斥系数的原理,这个可以做到√N的时间效率得到答案;今天又好好学习了一下莫比乌斯反演,不是那么的懵逼了,再莫比乌斯反演中,分块的思想可以大幅的提升时间效率,还是要做些题熟悉熟悉,具体的公式就不推了
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <iostream> 6 #include <algorithm> 7 using namespace std; 8 # define maxN 30000010 9 # define mod 76543 10 typedef long long LL; 11 LL n,N; 12 int su[maxN],mu[maxN],tot; 13 bool nosu[maxN]; 14 void Find_mu(){ 15 N=maxN-10; 16 mu[1]=1; 17 for(int i=2;i<=N;i++){ 18 if(!nosu[i]){ 19 su[++tot]=i; mu[i]=-1; 20 } 21 for(int j=1;j<=tot;j++){ 22 if((LL)i*su[j]>N) break; 23 nosu[i*su[j]]=1; 24 if(i%su[j]==0){mu[i*su[j]]=0; break;} 25 mu[i*su[j]]=-mu[i]; 26 } 27 } 28 for(int i=1;i<=N;i++) mu[i]+=mu[i-1]; 29 } 30 struct node{ 31 LL v,w; int nxt; 32 }g[maxN/10]; 33 int adj[80010],e; 34 void add(int u,LL v,LL w){ 35 g[e].v=v; g[e].w=w; g[e].nxt=adj[u]; 36 adj[u]=e++; 37 } 38 LL ps(LL x){ 39 if(x<=N) return mu[x]; 40 int k=x%mod; 41 for(int i=adj[k];i!=-1;i=g[i].nxt) 42 if(g[i].v==x) return g[i].w; 43 LL ans=1; LL nxt; 44 for(LL i=2;i<=x;i=nxt+1){ 45 nxt=(x/(x/i)); 46 ans-=(nxt-i+1)*ps(x/i); 47 } 48 add(k,x,ans); 49 return ans; 50 51 } 52 LL find(LL i,LL j){ 53 return ps(j)-ps(i-1); 54 } 55 int main(){ 56 // freopen("123567_20.in","r",stdin); 57 // freopen("666.out","w",stdout); 58 scanf("%lld",&n); 59 Find_mu(); 60 LL nxt; LL ans=0; 61 memset(adj,-1,sizeof(adj)); 62 LL lim=sqrt(n); 63 // ot(); 64 for(LL i=1;i<=lim;i=nxt+1){ 65 nxt=sqrt(n/(n/(i*i))); 66 ans+=n/(i*i)*find(i,nxt); 67 } 68 cout<<ans<<endl; 69 }
T3直接用Treap模拟可以拿到60,现在平衡树发现自己只会无旋Treap了,有时间要把Splay看一看,然后正解是线段树,就是利用平衡树中的中序遍历就是原序列,可以直接把一个平衡树拍成一个序列,然后可以发现,对于某一个点,他的左边的以他自己为起点上升序列长度+右边以他自己为起点上升序列长度,就是他的深度,为什么的话,可以找到,再这个序列中,一个点的左子树和右子树分别在这个点的左右两边,又因为这是一个大根堆,那么反过来,这个点可能在他的祖先(不一定是父亲)的右子树或者左子树,所以他的每一个祖先可能不再同一侧,而一个祖先有一定比他的孩子的权值大(大根堆),所以上升序列的长度和就是深度; 然后就是怎么用线段树维护这个上升序列,这个线段树里的update是递归实现的,这个之前没有遇到过,其实就是讨论一个子树中左右区间的影响关系,然后递归实现就行了,要注意的是合并子树信息是的顺序;还有一点两个点的LCA就是在序列中两个点之间的最大值(可以用最基本的线段树查询实现);
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #pragma GCC optimize("O3") 2 #include <cmath> 3 #include <cstdio> 4 #include <ctime> 5 #include <cstring> 6 #include <cstdlib> 7 #include <iostream> 8 #include <algorithm> 9 # define maxn 200010 10 using namespace std; 11 void ot(){cout<<"******"<<endl;} 12 struct QQ{ 13 int od,x,y; 14 }q[maxn]; 15 typedef pair<int,int> D; 16 D Max(D a,D b){return a.first>b.first? a:b;} 17 int n,m,N; 18 int hs[maxn]; 19 int ans1[4*maxn],ans2[4*maxn]; 20 D mx[4*maxn]; 21 bool cmp1(const int a,const int b){return a<b;} 22 void lsan(){ 23 sort(hs+1,hs+N+1,cmp1); 24 int cnt=unique(hs+1,hs+N+1)-hs-1; 25 for(int i=1;i<=n;i++){ 26 if(q[i].od==2){ 27 q[i].x=lower_bound(hs+1,hs+cnt+1,q[i].x)-hs; 28 q[i].y=lower_bound(hs+1,hs+cnt+1,q[i].y)-hs; 29 } 30 else q[i].x=lower_bound(hs+1,hs+cnt+1,q[i].x)-hs; 31 } 32 N=cnt; 33 } 34 void init(){ 35 scanf("%d",&n); 36 for(int i=1;i<=n;i++){ 37 scanf("%d",&q[i].od); 38 if(q[i].od==0){ 39 scanf("%d%d",&q[i].x,&q[i].y); 40 hs[++N]=q[i].x; 41 } 42 if(q[i].od==1){ 43 scanf("%d",&q[i].x); 44 } 45 if(q[i].od==2){ 46 scanf("%d%d",&q[i].x,&q[i].y); 47 if(q[i].x>q[i].y) swap(q[i].x,q[i].y); 48 } 49 } 50 lsan(); 51 } 52 int cal1(int now,int l,int r,int h){ 53 if(l==r) return mx[now].first>h? 1:0; 54 if(h>mx[now].first) return 0; 55 int mid=(l+r)>>1; 56 if(mx[now<<1].first<=h) return cal1(now<<1|1,mid+1,r,h); 57 else return cal1(now<<1,l,mid,h)+ans1[now]-ans1[now<<1]; 58 } 59 int cal2(int now,int l,int r,int h){ 60 if(l==r) return mx[now].first>h? 1:0; 61 if(h>mx[now].first) return 0; 62 int mid=(l+r)>>1; 63 if(mx[now<<1|1].first<=h) return cal2(now<<1,l,mid,h); 64 else return cal2(now<<1|1,mid+1,r,h)+ans2[now]-ans2[now<<1|1]; 65 } 66 void change(int ch,int now,int l,int r,int num){ 67 if(l==r){ 68 ans1[now]=ans2[now]=1; mx[now]=D(num,l); return; 69 } 70 int mid=(l+r)>>1; 71 if(ch<=mid) change(ch,now<<1,l,mid,num); 72 if(ch>mid) change(ch,now<<1|1,mid+1,r,num); 73 mx[now]=max(mx[now<<1],mx[now<<1|1]); 74 ans1[now]=ans1[now<<1]+cal1(now<<1|1,mid+1,r,mx[now<<1].first); 75 ans2[now]=ans2[now<<1|1]+cal2(now<<1,l,mid,mx[now<<1|1].first); 76 } 77 D query3(int left,int right,int now,int l,int r){ 78 if(left<=l && r<=right) return mx[now]; 79 int mid=(l+r)>>1; 80 D ret; 81 if(left<=mid) ret=max(ret,query3(left,right,now<<1,l,mid)); 82 if(right>mid) ret=max(ret,query3(left,right,now<<1|1,mid+1,r)); 83 return ret; 84 } 85 struct RRR{ 86 int ans,rt,l,r,mx; 87 RRR(int a = 0,int b = 0,int c = 0,int d = 0,int e = 0){ 88 ans=a; rt=b; l=c; r=d; mx=e; 89 } 90 }; 91 RRR Mer1(RRR a,RRR b){ 92 if(a.ans==-1) return b; 93 if(b.ans==-1) return a; 94 RRR ret; 95 ret.mx=max(a.mx,b.mx); 96 ret.ans=a.ans+cal1(b.rt,b.l,b.r,a.mx); 97 return ret; 98 } 99 RRR query1(int left,int right,int now,int l,int r){ 100 if( left<=l && r<=right){ 101 return RRR(ans1[now],now,l,r,mx[now].first); 102 } 103 int mid=(l+r)>>1; 104 RRR a,b,ret; a.ans=-1,b.ans=-1; 105 if(left<=mid) a=query1(left,right,now<<1,l,mid); 106 if(right>mid) b=query1(left,right,now<<1|1,mid+1,r); 107 ret=Mer1(a,b); 108 return ret; 109 } 110 RRR Mer2(RRR a,RRR b){ 111 if(a.ans==-1) return b; 112 if(b.ans==-1) return a; 113 RRR ret; 114 ret.mx=max(a.mx,b.mx); 115 ret.ans=b.ans+cal2(a.rt,a.l,a.r,b.mx); 116 return ret; 117 } 118 RRR query2(int left,int right,int now,int l,int r){ 119 if(left<=l && r<=right){ return RRR(ans2[now],now,l,r,mx[now].first);} 120 int mid=(l+r)>>1; 121 RRR a,b,ret; a.ans=-1,b.ans=-1; 122 if(right>mid) b=query2(left,right,now<<1|1,mid+1,r); 123 if(left<=mid) a=query2(left,right,now<<1,l,mid); 124 return Mer2(a,b); 125 return ret; 126 } 127 void work(){ 128 for(int i=1;i<=n;i++){ 129 if(q[i].od==0){ 130 change(q[i].x,1,1,N,q[i].y); 131 // cout<<q[i].x<<endl; 132 } 133 if(q[i].od==1){ 134 change(q[i].x,1,1,N,0); 135 } 136 if(q[i].od==2){ 137 // printf("pos== %d %d\n",q[i].x,q[i].y ); 138 int dx=query1(q[i].x,N,1,1,N).ans+query2(1,q[i].x,1,1,N).ans; //query1(q[i].x,N,1,1,N).ans+ 139 int dy=query1(q[i].y,N,1,1,N).ans+query2(1,q[i].y,1,1,N).ans; 140 int k=query3(q[i].x,q[i].y,1,1,N).second; 141 int dl=query1(k,N,1,1,N).ans+query2(1,k,1,1,N).ans; 142 // printf("ans== %d %d\n",ans1[1],ans2[1]); 143 // printf("k= %d\n",k); 144 // printf("dep== %d %d %d\n",dx,dy,dl); 145 printf("%d\n",dx+dy-2*dl); 146 } 147 // if(i==5) exit(0); 148 } 149 } 150 int main(){ 151 // freopen("treap_1.in","r",stdin); 152 // freopen("666.out","w",stdout); 153 init(); 154 work(); 155 }