2021.8.9考试总结[NOIP模拟34]
T1 Merchant
如果$t=0$时不能达到$s$,那么所拿物品的价值一定关于时间单调递增,答案单调。因此可以特判$0$后二分。
用$sort$复杂度被卡,要用$\textit{nth_element}$,相当于$sort$只递归一边,均摊$O(n)$。
$check$时遇到小于零的直接跳过,达到$s$后直接$return$,不然可能爆$\textit{long long}$。
$code:$
1 #include<bits/stdc++.h> 2 #define int long long 3 #define rin register signed 4 using namespace std; 5 const int NN=1e6+5; 6 int n,m,s,spj,ans,l,r=1e9,mid,tmp[NN]; 7 struct line{ int k,b; }ln[NN]; 8 inline bool cmp(line a,line c){ return a.b>c.b;} 9 inline bool cmpn(int a,int b){ return a>b; } 10 inline int read(){ 11 int x=0,f=1; char ch=getchar(); 12 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 13 while(ch<='9'&&ch>='0'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 14 return x*f; 15 } 16 inline void write(int x){ 17 char ch[20]; int len=0; 18 if(x<0) x=~x+1, putchar('-'); 19 do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x); 20 for(rin i=len-1;i>=0;--i) putchar(ch[i]); 21 } 22 inline bool check(int mid){ 23 int res=0; 24 for(int i=1;i<=n;i++) tmp[i]=ln[i].k*mid+ln[i].b; 25 nth_element(tmp+1,tmp+m+1,tmp+n+1,cmpn); 26 for(int i=1;i<=m;i++){ 27 if(tmp[i]<=0) continue; 28 res+=tmp[i]; 29 if(res>=s) return 1; 30 } 31 return 0; 32 } 33 signed main(){ 34 n=read(); m=read(); s=read(); 35 for(rin i=1;i<=n;i++) 36 ln[i].k=read(), ln[i].b=read(); 37 sort(ln+1,ln+n+1,cmp); 38 for(int i=1;i<=m;i++){ 39 spj+=ln[i].b; 40 if(spj>=s){ puts("0"); return 0; } 41 } 42 while(l<=r){ 43 mid=l+r>>1; 44 if(check(mid)) ans=mid, r=mid-1; 45 else l=mid+1; 46 } 47 write(ans); putchar('\n'); 48 return 0; 49 }
T2 Equation
可以在$DFS$中求出当前点u与一号节点形成的式子,同时可以通过该点深度得到与一号节点形成的式子是加是减。然后简单消元可以得到想要的方程,直接求解判断即可。
修改时要修改子树中所有节点,在$DFS$序上建两个差分树状数组,一个记加法节点,一个记减法节点,修改时操作相反。
其实一个树状数组也行,用时取负即可。
$code:$
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 const int NN=1e6+5; 5 int n,q,to[NN<<1],nex[NN<<1],head[NN],num,w[NN],op,u,v,ww; 6 int typ[NN],dep[NN],siz[NN],dfn[NN],cnt; 7 struct tr{ 8 int c[NN]; 9 int lowbit(int x){ return x&(-x); } 10 void insert(int val,int pos){ 11 while(pos<=n){ 12 c[pos]+=val; 13 pos+=lowbit(pos); 14 } 15 } 16 int query(int pos){ 17 int res=0; 18 while(pos){ 19 res+=c[pos]; 20 pos-=lowbit(pos); 21 } 22 return res; 23 } 24 }c[2]; 25 inline int read(){ 26 int x=0,f=1; char ch=getchar(); 27 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 28 while(ch<='9'&&ch>='0'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 29 return x*f; 30 } 31 inline void write(int x){ 32 char ch[20]; int len=0; 33 if(x<0) x=~x+1, putchar('-'); 34 do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x); 35 for(int i=len-1;i>=0;--i) putchar(ch[i]); 36 } 37 inline void add(int a,int b){ 38 to[++num]=b; nex[num]=head[a]; head[a]=num; 39 to[++num]=a; nex[num]=head[b]; head[b]=num; 40 } 41 void dfs(int f,int s,int pre){ 42 dep[s]=dep[f]+1; siz[s]=1; dfn[s]=++cnt; 43 typ[s]=(dep[s]&1)?0:1; 44 c[typ[s]].insert(pre,dfn[s]); 45 c[typ[s]].insert(-pre,dfn[s]+1); 46 for(int i=head[s];i;i=nex[i]){ 47 int v=to[i]; 48 if(v==f) continue; 49 dfs(s,v,w[v]-pre); 50 siz[s]+=siz[v]; 51 } 52 } 53 void calc(int u,int v,int ww){ 54 int tu=typ[u],tv=typ[v],uu; 55 int wu=c[tu].query(dfn[u]);//-c[tu].query(dfn[u]-1); 56 int wv=c[tv].query(dfn[v]);//-c[tv].query(dfn[v]-1); 57 if(tu^tv){ puts((wu+wv)==ww?"inf":"none"); return; } 58 if((ww+wu-wv)&1){ puts("none"); return; } 59 uu=(ww+wu-wv)>>1; 60 write(tu?(wu-uu):(uu-wu)); putchar('\n'); 61 } 62 signed main(){ 63 n=read(); q=read(); 64 for(int i=2;i<=n;i++){ 65 int tmp=read(); add(i,tmp); 66 w[i]=read(); 67 } dfs(0,1,0); 68 while(q--){ 69 op=read(); 70 if(op==1) u=read(), v=read(), ww=read(), calc(u,v,ww); 71 else{ 72 u=read(); int tmp=w[u]; w[u]=read(); 73 c[typ[u]].insert(w[u]-tmp,dfn[u]); 74 c[typ[u]].insert(tmp-w[u],dfn[u]+siz[u]); 75 c[typ[u]^1].insert(tmp-w[u],dfn[u]); 76 c[typ[u]^1].insert(w[u]-tmp,dfn[u]+siz[u]); 77 } 78 } 79 return 0; 80 }
T3 Rectangle
好像能扫描线做?但不会。
首先考虑坐标不重的情况。枚举矩形右边界$i$,再向左枚举左边界$j$,然后考虑左右边界中的点。
记矩形至少的上界为$y_x$,至多的下界为$y_n$,那么这四个边界对答案的贡献:
$(i-j)\times \sum_{p<y_n} \sum_{q>y_x}(y_x-y_n)$
记录大于$y_x$和小于$y_n$的点的个数与总和,两两相乘再相减即可。
考虑可重的情况。这时因为左右边界有很多点,同一矩形就可能被重复计算。利用这些点把大矩形分为若干个小矩形分别计算即可。
$code:$
1 #include<bits/stdc++.h> 2 #define int long long 3 #define pb push_back 4 using namespace std; 5 const int NN=1e4+5,p=1e9+7; 6 int n,ans; 7 bool vis[2501][2501]; 8 vector<int>sub[2501]; 9 inline int read(){ 10 int x=0,f=1; char ch=getchar(); 11 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 12 while(ch<='9'&&ch>='0'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 13 return x*f; 14 } 15 inline void write(int x){ 16 char ch[20]; int len=0; 17 if(x<0) x=~x+1, putchar('-'); 18 do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x); 19 for(int i=len-1;i>=0;--i) putchar(ch[i]); 20 } 21 struct trearray{ 22 int c[2501][2]; 23 void insert(int k,int x,int pos){ 24 while(pos<=2500){ 25 c[pos][k]+=x; 26 pos+=(pos&(-pos)); 27 } 28 } 29 int query(int k,int pos){ 30 int res=0; 31 while(pos){ 32 res+=c[pos][k]; 33 pos-=(pos&(-pos)); 34 } 35 return res; 36 } 37 }t[2501]; 38 signed main(){ 39 n=read(); 40 for(int i=1;i<=n;i++){ 41 int x=read(),y=read(); 42 sub[x].pb(y); 43 } 44 for(int i=1;i<=2500;i++){ 45 sort(sub[i].begin(),sub[i].end()); 46 sub[i].pb(2501); 47 } 48 for(int i=1;i<=2500;i++){ 49 if(sub[i].size()==1) continue; 50 for(int j=0;j<sub[i].size()-1;j++) if(!vis[i][sub[i][j]]){ 51 vis[i][sub[i][j]]=1; 52 t[i].insert(0,sub[i][j],sub[i][j]); 53 t[i].insert(1,1,sub[i][j]); 54 } 55 for(int j=i-1;j;j--){ 56 if(sub[j].size()==1) continue; 57 for(int k=0;k<sub[j].size()-1;k++) if(!vis[i][sub[j][k]]){ 58 vis[i][sub[j][k]]=1; 59 t[i].insert(0,sub[j][k],sub[j][k]); 60 t[i].insert(1,1,sub[j][k]); 61 } 62 int lmt=max(sub[i][0],sub[j][0]),tmp1=0,tmp2=0,flag; 63 while(sub[i][tmp1+1]<=lmt) tmp1++; 64 while(sub[j][tmp2+1]<=lmt) tmp2++; 65 while(tmp1<sub[i].size()-1&&tmp2<sub[j].size()-1){ 66 flag=min(sub[i][tmp1+1],sub[j][tmp2+1]); 67 (ans+=(i-j)*(t[i].query(0,flag-1)-t[i].query(0,lmt-1))*t[i].query(1,min(sub[i][tmp1],sub[j][tmp2])))%=p; 68 (ans-=(i-j)*(t[i].query(1,flag-1)-t[i].query(1,lmt-1))*t[i].query(0,min(sub[i][tmp1],sub[j][tmp2])))%=p; 69 (ans+=p)%=p; 70 lmt=flag; 71 if(sub[i][tmp1+1]<=lmt) tmp1++; 72 if(sub[j][tmp2+1]<=lmt) tmp2++; 73 } 74 } 75 } 76 write(ans); putchar('\n'); 77 return 0; 78 }