二次元音游人

这是一股照亮混沌的令和时代互联网的一道光,给在电子的海洋里冲浪的阿宅们带来笑容

怎么马上上大学了😭😭

暑假狠狠地颓了,玩了音游和mc(好玩喵)

高考完了上了兰州大学,但是继续颓(是因为学校有奥赛生政策导致的)

怎么还没上大学就有hzoi2021的大佬邀请我打ICPC网络赛啊😰😰😰,我真的很菜的(而且还没复建)(9.7就开始了😰😰🥵🥵😰😭😭😭😭)

希望不会给dalao拖后腿吧orz%%%

有问题评论区问我都可以回答喵🥵🥵

以下是复健过程:(始于8.16)

lca最近公共祖先

学了之后自己打了一遍倍增lca,有以下三个错误

1.dfs中


inline void dfs(int x,int fa){
    dep[x]=dep[fa]+1;
    Fa[x][0]=fa;
    for(register int i=head[x];i;i=nxt[i]){
        int y=to[i];
        if(vis[y]) continue;
        vis[y]=true;
        dis[y]=dis[x]+val[i];
        dfs(y,x);
    }
}

vis[y]=true 不能这样用,否则会导致 vis[1] 没有判定为 true ,后面会遍历到 1 导致出 bug

解决方案:在 dfs(1,0) 前加上 vis[1]=true 或者在 dfs 种改成 vis[x]=true


vis[x]=true;
    for(register int i=head[x];i;i=nxt[i]){
        int y=to[i];
        if(vis[y]) continue;
        dis[y]=dis[x]+val[i];
        dfs(y,x);
    }

2.弱智错误

if(dep[Fa[y][i]]>=dep[x]) 写成 if(dep[Fa[y][i]>=dep[x]]) 检查半天

3.深度反了

  for(register int i=log2n;i>=0;i--){
        if(dep[Fa[y][i]]>=dep[x]){
            y=Fa[y][i];
        }
    }

注意是 不是 !!!
放上 lca 子题代码

F. Distance Queries 距离咨询

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=40005;
inline int read(){
    int f(1),x(0);
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-48;
    return f*x;
}
inline void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int head[N],nxt[N<<1],to[N<<1],tot,val[N<<1];
inline void add(int x,int y,int Val){
    to[++tot]=y,nxt[tot]=head[x],head[x]=tot,val[tot]=Val;
}
int n,m;
int log2n;
bool vis[N];
int dep[N],Fa[N][22],dis[N];
inline void dfs(int x,int fa){
    dep[x]=dep[fa]+1;
    Fa[x][0]=fa;
    vis[x]=true;
    for(register int i=head[x];i;i=nxt[i]){
        int y=to[i];
        if(vis[y]) continue;
        dis[y]=dis[x]+val[i];
        dfs(y,x);
    }
}
inline int lca(int x,int y){
    if(dep[x]>dep[y]) swap(x,y);
    for(register int i=log2n;i>=0;i--){
        if(dep[Fa[y][i]]>=dep[x]){
            y=Fa[y][i];
        }
    }
    if(x==y) return x;
    for(register int i=log2n;i>=0;i--){
        if(Fa[x][i]==Fa[y][i]){
            continue;
        }
        x=Fa[x][i],y=Fa[y][i];
    }
    return Fa[x][0];
}
main(void){
    n=read(),m=read();
    log2n=log2(n)+1;
    while(m--){
        int a=read(),b=read(),V=read();
        char dsakjhd=getchar();
        add(a,b,V),add(b,a,V);
    }
    dfs(1,0);
    for(register int j=1;j<=log2n;j++){
        for(register int i=1;i<=n;i++){
            Fa[i][j]=Fa[Fa[i][j-1]][j-1];
        }
    }
    int k=read();
    while(k--){
        int a=read(),b=read();
        write(dis[a]+dis[b]-2*dis[lca(a,b)]),puts("");
    }
    return 0;
}

话说我连 markdown 怎么打都忘了怎么办😭😭😭😭😰😰

tarjan 好麻烦不想学

bzoj 3306 树

涉及了换根和 \(dfs\) 序维护最小值。难度为紫题

不会换根,看了一下思路之后自己狠狠打了一个半小时得了9分。

死因为两点:

\(1\)

change(1,1,n,in[x],y);//忘了写成 in[x]

\(2\)

	inline int query(int root,int l,int r,int L,int R){
		if(L>R) return LONG_LONG_MAX;//没有特判这个b玩意
		if(L<=l&&R>=r){//这个大小于号写反了,实际上应该是
		//----------------------------------------------------
		//      L      l     r     R
			return Min[root];
		}
		int mid=(l+r)>>1;
		int A=LONG_LONG_MAX;
		if(L<=mid) A=min(A,query(lid,l,mid,L,R));
		if(R>mid) A=min(A,query(rid,mid+1,r,L,R));
		return A;
	}

\(3\) 这个是没看题解没弄出来的,纯没想到

	else if(in[RT]>=in[x]&&out[RT]<=out[x]){//如果RT在x的子树需要特殊查询
             int Z=find(x,RT);
             write(min(query(1,1,n,1,in[Z]-1),query(1,1,n,out[Z]+1,n))),puts("");
         }

换根,除了 \(rt\)\(x\) 的这部分路径,树上其他全都算上。

因为如果 \(rt\) 属于 \(x\) 的子树的话,从 \(rt\)\(x\) 是树最上面的部分,除了离 \(x\) 最近的这个儿子节点,其他都是深度最小的。所以应该是 min(query(1,1,n,1,in[Z]-1),query(1,1,n,out[Z]+1,n))

而不是 min(query(1,1,n,in[x],in[Z]-1,query(1,1,n,out[Z]+1,out[x])))

\(8.17\)

树链剖分详解,看这一篇就够了

先把昨天的 \(bzoj\) 树做完了。

学了一点树链刨分,打了树链刨分求 \(lca\) 板子题。感觉好摆

树链刨分最重要的是把树拆出来若干重链,然后求 \(lca\) 的话

\(1\). 在同一条重链的话,\(lca\) 就是深度较浅的那一个点

\(2\). 不在同一条重链的话,\(lca\) 就看两个点所在的重链头部,把深度较深的那个头部的点跳到重链头部的父亲节点,这样的话就能把这个点往上面的链跳一步。如此循环跳,直到在同一重链。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e5+5;
inline int read(){
	int f(1),x(0);
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-48;
	return f*x;
}
inline void write(int x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10+'0');
}
int head[N],nxt[N<<1],to[N<<1],tot;
inline void add(int x,int y){
    to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
    return;
}
int F[N],dep[N],siz[N],son[N];
inline void dfs1(int now,int fa){
    dep[now]=dep[fa]+1;
    F[now]=fa;
    siz[now]=1;
    for(register int i=head[now];i;i=nxt[i]){
        int y=to[i];
        if(y==fa) continue;
        dfs1(y,now);
        siz[now]+=siz[y];
        if(!son[now]||siz[y]>=siz[son[now]]){
            //if(siz[y]>=siz[son[now]])
            son[now]=y;
        }
    }
}
int top[N];
inline void dfs2(int now,int TOP){
    top[now]=TOP;
    if(son[now]){
        dfs2(son[now],TOP);
    }
    for(register int i=head[now];i;i=nxt[i]){
        int y=to[i];
        if(y==F[now]||y==son[now]){
            continue;
        }
        dfs2(y,y);
    }
}
inline int lca(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]>=dep[top[y]]){
            x=F[top[x]];
        }
        else{
            y=F[top[y]];
        }
    }
    return dep[x]<=dep[y]?x:y;
}
int n,m,rt;
main(void){
    n=read(),m=read(),rt=read();
    for(register int i=1;i<=n-1;i++){
        int a=read(),b=read();
        add(a,b),add(b,a);
    }
    dfs1(rt,0);
    dfs2(rt,rt);
    while(m--){
        int a=read(),b=read();
        write(lca(a,b)),puts("");
    }
    return 0;
}

\(8.18\)

起来先把昨天熬夜打的树链刨分线段树模板改完

19分求调教❤,刚复健便遇滑铁卢之不应该在睡前打代码的😭😭😭

原因是 你线段树里面用的 siz 是直接把 dfs 整棵树时候的 siz 拿来用了

把线段树里的区间长度单独算一下就行了 \(SZ[x]\)

注意 \(SZ[x]\) 也要开 \(4\) 倍空间!!!

下面是提交记录

欸 🤓☝给大家看看我造的房子(

2025-08-18_16.17.21

(还是太颓了

接下来学什么好呢。

打算看一下 \(icpc\) 原题试试,虽然只学了几个数据结构,还没学有思维的算法呢。😭😭😭😭😭😭

然後被 \(icpc\) 薄紗了。😭😭😭😭😭😭

image

8.19日

复习了一下单调栈,被薄纱了,还是会最基础的单调栈。。。

自己打的P2659 美丽的序列

main(void){
    n=read();
    for(register int i=1;i<=n;i++){
        a[i]=read();
    }
    int ans=-114514;
    a[n+1]=-114514;
    for(register int i=1;i<=n;i++){
        while(top&&a[i]<=a[stk[top]]){
            top--;
        }
        zuo[i]=stk[top]+1;
        stk[++top]=i;
    }
    stk[top=0]=n+1;
    for(register int i=n;i>=1;i--){
        while(top&&a[i]<=a[stk[top]]){
            top--;
        }
        you[i]=stk[top]-1;
        stk[++top]=i;
    }
    for(register int i=1;i<=n;i++){
        ans=max(ans,(you[i]-zuo[i]+1)*a[i]);
    }
    write(ans);
    return 0;
}

为了打这道题,专门复习了对拍(我怎么这么菜😭😭😭😭

另外,我已经掌握了对拍力(喜!

while(1){
     system("data.exe > data.in");
     system("baoli.exe < data.in > baoli.out");
     system("now.exe < data.in > now.out");
     if(system("fc baoli.out now.out")) return 0;
}

< 意思为从哪读入,> 为输出到哪里

fc 1.out 2.out 即可核对 1.out2.out 的差异了。

学了模拟退火

平衡点

放上代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
   int f(1),x(0);
   char ch=getchar();
   for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
   for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-48;
   return f*x;
}
inline void write(int x){
   if(x<0) putchar('-'),x=-x;
   if(x>9) write(x/10);
   putchar(x%10+'0');
}
const int N=1024;
struct  node{
    int x,y,w;
}a[N];
int n;
mt19937 rd(chrono::system_clock::now().time_since_epoch().count());
inline int R(){
    int sb=rd();
    return (sb%20000)-10000;
}
inline double energy(double x,double y){
    double ANS=0;
    for(register int i=1;i<=n;i++){
        double deltax=a[i].x-x;
        double deltay=a[i].y-y;
        ANS+=sqrt(deltax*deltax+deltay*deltay)*a[i].w;
    }
    return ANS;
}
double Ansx,Ansy;
double ansx,ansy,answ;
inline void SA(){
    double T=1000;
    while((double)clock()/CLOCKS_PER_SEC<0.995){
        double nowx=ansx+R()*T;
        double nowy=ansy+R()*T;
        double noww=energy(nowx,nowy);
        double delta=answ-noww;
        if(noww<answ){ 
            answ=noww,ansx=nowx,ansy=nowy;
            Ansx=ansx,Ansy=ansy;
        }
        else if(exp(-fabs(delta)/T)*RAND_MAX>rand()){
            ansx=nowx,ansy=nowy;
       }
       T*=0.9995;
    }
    printf("%.3lf %.3lf",Ansx,Ansy);
}
main(void){
    srand(time(0));
    n=read();
    for(register int i=1;i<=n;i++){
        a[i].x=read(),a[i].y=read(),a[i].w=read();
        ansx+=a[i].x,ansy+=a[i].y;
    }
    ansx/=n,ansy/=n;
    answ=energy(ansx,ansy);
    Ansx=ansx,Ansy=ansy;
    SA();
    return 0;
}

重要的是 exp(-fabs(delta)/T)*RAND_MAX>rand() 处,\(delta\) 一定是个负数,所以直接上 -fabs(delta) 就行了(喜

放上模拟退火链接

8.20

P1248 加工生产调度 这个题用模拟退火轻松做

终于算是掌握了模拟退火力(喜

P5356 由乃打扑克

自己做出来分块了(调出来两个错误!多亏了对拍orz

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
   int f(1),x(0);
   char ch=getchar();
   for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
   for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-48;
   return f*x;
}
inline void write(int x){
   if(x<0) putchar('-'),x=-x;
   if(x>9) write(x/10);
   putchar(x%10+'0');
}
int n,m;
const int N=1e5+5;
int blk[N],a[N],b[N],q;
int L[N],R[N];
inline void rebuild(int x){//重建第几块
   for(register int i=L[x];i<=R[x];i++){
      b[i]=a[i];
   }
   sort(b+L[x],b+R[x]+1);
}
int tag[N];//第几块的加法标记
inline void add(int l,int r,int k){
   if(blk[l]==blk[r]){
      for(register int i=l;i<=r;i++){
         a[i]+=k;
      }
      rebuild(blk[l]);
      return;
   }
   for(register int i=l;i<=R[blk[l]];i++){
      a[i]+=k;
   }
   rebuild(blk[l]);
   for(register int i=L[blk[r]];i<=r;i++){
      a[i]+=k;
   }
   rebuild(blk[r]);
   for(register int i=blk[l]+1;i<=blk[r]-1;i++){
      tag[i]+=k;
   }
   return;
}
inline pair<int,int> GetMaxMin(int l,int r){
   int Max=LONG_LONG_MIN,Min=LONG_LONG_MAX;
   if(blk[l]==blk[r]){
      for(register int i=l;i<=r;i++){
         Max=max(Max,a[i]+tag[blk[l]]);
         Min=min(Min,a[i]+tag[blk[l]]);
      }
      return make_pair(Max,Min);
   }
   for(register int i=l;i<=R[blk[l]];i++){
      Max=max(Max,a[i]+tag[blk[l]]);
      Min=min(Min,a[i]+tag[blk[l]]);   
   }
   for(register int i=L[blk[r]];i<=r;i++){
      Max=max(Max,a[i]+tag[blk[r]]);
      Min=min(Min,a[i]+tag[blk[r]]);   //错误1,把上面的粘贴过来忘了把 l 改成 r 😭😭😭😭
   }
   // cerr<<"asdasdasda"<<blk[l]+1<<"   "<<blk[r]-1<<endl;
   // cerr<<"Min:  "<<tag[i]<<"+"<<b[L[i]]<<endl;
   for(register int i=blk[l]+1;i<=blk[r]-1;i++){
      Max=max(Max,tag[i]+b[R[i]]);
      Min=min(Min,tag[i]+b[L[i]]);
   }
   return make_pair(Max,Min);
}
inline int Howmany(int l,int r,int x){//统计比x小的个数
   int ans=0;
   if(blk[l]==blk[r]){
      for(register int i=l;i<=r;i++){
         if(a[i]+tag[blk[i]]<x){
            ans++;
         }
      }
      return ans;
   }
   for(register int i=l;i<=R[blk[l]];i++){
      if(a[i]+tag[blk[i]]<x){
         ans++;
      }
   }

//    cerr<<"ans1:  "<<ans<<endl;
   for(register int i=L[blk[r]];i<=r;i++){
    // cerr<<a[i]+tag[blk[i]]<<"   "<<x<<endl;
      if(a[i]+tag[blk[i]]<x){
         ans++;
      }
    }
    // cerr<<"L[blk[r]]:"<<L[blk[r]]<<"     "<<r<<endl;
    // cerr<<"ans2:  "<<ans<<endl;
   for(register int i=blk[l]+1;i<=blk[r]-1;i++){
       if(b[L[i]]+tag[i]>x){
           continue;
        }
        if(b[R[i]]+tag[i]<x){
            ans+=R[i]-L[i]+1;
            continue;
        }
        // cerr<<"ans3:  "<<ans<<endl;
        ans+=lower_bound(b+L[i],b+R[i]+1,x-tag[i])-b-L[i]; //错误2,写成 L[blk[i]] 了,鉴定为块中块的闹谈
        // cerr<<"ans4:  "<<ans<<endl;
   }
   return ans;
}
inline int Kth(int l,int r,int k){
   auto p=GetMaxMin(l,r);
   int LL=p.second,RR=p.first,ans=-1;
//    cerr<<"L&R:  "<<LL<<"  "<<RR<<endl;
   while(LL<=RR){
      int mid=(LL+RR)>>1;
      int kk=Howmany(l,r,mid);
    //   cerr<<"!!:  "<<kk<<"   "<<mid<<endl;
      if(kk<k){
         ans=mid;
         LL=mid+1;
      }
      else{
         RR=mid-1;
      }
   }
   return ans;
}
main(void){
   // int ac[10]={0,1,2,4,5};
   // cerr<<lower_bound(ac+1,ac+4+1,2)-ac-1;
   // return 0;
   n=read(),m=read();
   q=sqrt(n);
   for(register int i=1;i<=n;i++){
      a[i]=read();
   }
   for(register int i=1;i<=n;i++){
      blk[i]=(i-1)/q+1;
      if(!L[blk[i]]){
         L[blk[i]]=i;
         R[blk[i]-1]=i-1;
      }
   }
   R[blk[n]]=n;
   // for(register int i=1;i<=3;i++){
   //    cerr<<i<<" "<<L[i]<<" "<<R[i]<<endl;
   // }
   for(register int i=1;i<=blk[n];i++){
      rebuild(i);
   }

   while(m--){
      int opt=read(),l=read(),r=read(),k=read();
      if(opt==1){
         if(k>(r-l+1)){
            puts("-1");
            continue;
         }
         write(Kth(l,r,k)),puts("");
      }
      else{
         add(l,r,k);
        //  for(register int i=1;i<=3;i++){
        //     cerr<<i<<" tag:"<<tag[i]<<endl;
        //  }
      }
   }
   return 0;
}
/*
5 3
3 2 2 4 1
1 4 5 1
2 1 5 1
1 4 5 1

*/

自己写出来还是挺爽的,另外推荐一下我做这道题时候的歌曲 夜明けと蛍 \(by n-buna\) 好听捏

8.21

太摆了,光打了一个熟练刨分。另外 衡中OI 炸了🥵😡😡

8.22

摆了

做了 P2824排序

这种二分加转化为 \(01\) 的思维很好

8.23

做了 \(dp_a\) , \(dp_b\) , \(dp_i\)

打算明天做剩下的。。

9.1

昨天刚报道就和学长学姐打了一场比赛,我 p 都不会怎么办😮😭😭

今天在宿舍调一下大模拟代码发现调不出来了😭😭😭样例都模不明白

明天还要闹谈军训 \(R.I.P.\)

posted @ 2025-08-16 16:29  超绝最可爱天使酱  阅读(32)  评论(3)    收藏  举报