P1081 (倍增+代码实现技巧)
在写提前先花一点时间想好自己的代码里有什么,这样就不用像我这样调一天了。然后在遇到比较相似的代码时,可以考虑并到一个函数里,比如说push_up和getsum里对左区间和右区间的合并,我一般是写在一个函数里的qwq。
在调了超过2h时可以考虑重复上面的过程(重构在思路清晰的情况下是很快的,反正我重构只花了1h)
这题其实还是比较简单的,有点像大模拟。思路非常简单。在看到对一个静态的区间求max/min时我们可以想到使用RMQ,在看到对一个静态的区间求(任何具有结合律的运算,像和,max/min(虽然时间复杂度不优),矩阵乘法,快速幂)时可以想到倍增,而带修时,就想到各种ds了。
看到对数组中两个数的abs取min,并且是有顺序的,可以考虑平衡树(我不会链表qwq)
好讲完这题思路的来源就可以放代码了
#include<bits/stdc++.h>
using namespace std;
struct grg{
long long val,id;
bool g;
}g[7];
bool cmp(grg x,grg y){
if(x.val==y.val) return x.g<y.g;
return x.val<y.val;
}
long long n,h[100005],x,T,s,dp[100005][20][2],tar[100005][2],atar[100005][20],btar[100005][20];//从i城市往前开2^i轮
//-----------------fhq-treap-----------------------
struct node{
long long val,rd;
}p[100005];
long long root,size[100005],son[100005][2],cnt=0,rx,ry,rz;
void update(long long rt){
size[rt]=size[son[rt][0]]+size[son[rt][1]]+1;
}
long long add(long long x){
cnt++;
size[cnt]=1;
p[cnt].val=x;
p[cnt].rd=rand();
return cnt;
}
void split(long long rt,long long key,long long &x,long long &y){
if(!rt){
x=y=0;
return;
}
if(p[rt].val<=key){
x=rt;
split(son[rt][1],key,son[rt][1],y);
}
else{
y=rt;
split(son[rt][0],key,x,son[rt][0]);
}
update(rt);
}
void split1(long long rt,long long siz,long long &x,long long &y) {
if(!rt){
x=y=0;
return;
}if(size[son[rt][0]]>=siz){
y=rt;
split1(son[rt][0],siz,x,son[rt][0]);
}else{
x=rt;
split1(son[rt][1],siz-(size[son[rt][0]]+1),son[rt][1],y);
}
update(rt);
}
long long merge(long long l,long long r){
if(!l||!r) return l+r;
if(p[l].rd<p[r].rd){
son[l][1]=merge(son[l][1],r);
update(l);
return l;
}else{
son[r][0]=merge(l,son[r][0]);
update(r);
return r;
}
}
long long getrnk(long long x,long long k){
if(!x) return 0;
while(true){
if(k<=size[son[x][0]]) x=son[x][0];
else if(k>size[son[x][0]]+1){
k-=(size[son[x][0]]+1);
x=son[x][1];
}
else return x;
}
}
void insert(long long x){
split(root,x,rx,ry);
root=merge(merge(rx,add(x)),ry);
}//插入x
//-----------------fhq-treap-----------------------
bool eq(double x,double y){
if(fabs(x-y)<=1e-6) return true;
return false;
}
void solve(long long u,long long top,long long &x,long long &y){//起点 距离 A B
x=y=0;
for(long long i=19;i>=0;i--){
//cout<<u<<" "<<i<<":"<<dp[u][i][0]<<" "<<dp[u][i][1]<<"\n";
if((dp[u][i][0]+dp[u][i][1]<=top)&&atar[u][i]){
x+=dp[u][i][0];
y+=dp[u][i][1];
top-=(dp[u][i][0]+dp[u][i][1]);
u=atar[u][i];
}
}
if(tar[u][0]&&abs(h[u]-h[tar[u][0]])<=top) x+=abs(h[u]-h[tar[u][0]]);
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
srand(time(0));
memset(dp,0x3f,sizeof(dp));
cin>>n;
for(long long i=1;i<=n;i++){
cin>>h[i];
}
for(long long i=n;i>=1;i--){
for(long long j=1;j<=4;j++) g[1].val=g[2].val=g[3].val=g[4].val=1e16;
split(root,h[i],rx,ry);
if(size[rx]>=2){
g[1].id=n-getrnk(rx,size[rx]-1)+1;
g[1].val=abs(h[g[1].id]-h[i]);
if(h[g[1].id]<h[i]) g[1].g=0;
else g[1].g=1;
}if(size[rx]){
g[2].id=n-getrnk(rx,size[rx])+1;
g[2].val=abs(h[g[2].id]-h[i]);
if(h[g[2].id]<h[i]) g[2].g=0;
else g[2].g=1;
}if(size[ry]){
g[3].id=n-getrnk(ry,1)+1;
g[3].val=abs(h[g[3].id]-h[i]);
if(h[g[3].id]<h[i]) g[3].g=0;
else g[3].g=1;
}if(size[ry]>=2){
g[4].id=n-getrnk(ry,2)+1;
g[4].val=abs(h[g[4].id]-h[i]);
if(h[g[4].id]<h[i]) g[4].g=0;
else g[4].g=1;
}
root=merge(rx,ry);
sort(g+1,g+5,cmp);
if(g[1].val!=1e16) tar[i][1]=g[1].id;
if(g[2].val!=1e16) tar[i][0]=g[2].id;
insert(h[i]);
}
//tar[n][0]=tar[n][1]=n+1;
for(long long i=1;i<=n;i++){
if(tar[tar[i][0]][1]){
dp[i][0][0]=abs(h[i]-h[tar[i][0]]);
dp[i][0][1]=abs(h[tar[i][0]]-h[tar[tar[i][0]][1]]);
atar[i][0]=tar[tar[i][0]][1];
}
}
for(long long j=1;j<=19;j++){
for(long long i=1;i<=n;i++){
if(atar[atar[i][j-1]][j-1]){
atar[i][j]=atar[atar[i][j-1]][j-1];
dp[i][j][0]=dp[i][j-1][0]+dp[atar[i][j-1]][j-1][0];
dp[i][j][1]=dp[i][j-1][1]+dp[atar[i][j-1]][j-1][1];
}
}
}
long long maxh=-1,ans=0;
double minn=1e9;
cin>>x;
//solve(2,x,rx,ry);
//cout<<rx<<"-"<<ry<<endl;
for(long long i=1;i<=n;i++){
solve(i,x,rx,ry);
if(ry==0){
if(eq(minn,1e9)){
if(h[i]>maxh){
maxh=h[i];
ans=i;
}
}
}else{
if(eq((double)rx,(double)ry*minn)){
if(h[i]>maxh){
maxh=h[i];
ans=i;
}
}else if((double)rx<(double)ry*minn){
minn=(double)rx/(double)ry;
maxh=h[i];
ans=i;
}
}
}
cout<<ans<<"\n";
cin>>T;
while(T--){
cin>>s>>x;
solve(s,x,rx,ry);
cout<<rx<<" "<<ry<<"\n";
}
return 0;
}