2021.9.9考试总结[NOIP模拟50]

T1 第零题


神秘结论:从一个点满体力到另一个点的复活次数与倒过来相同。

于是预处理出每个点向上走第$2^i$个死亡点的位置,具体实现可以倍增或二分。

每次询问先从两个点同时向上倍增,都转到离$LCA$最近的死亡点上,然后判断,如果现在两点路径上权值大于$k$则答案加$1$。

$code:$

2021.9.9考试总结[NOIP模拟50]
 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 
 5 namespace IO{
 6     inline int read(){
 7         char ch=getchar(); int x=0,f=1;
 8         while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 9         while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
10         return x*f;
11     }
12     inline void write(int x,char sp){
13         char ch[20]; int len=0;
14         if(x<0){ putchar('-'); x=~x+1; }
15         do{ ch[len++]=x%10+(1<<4)+(1<<5); x/=10; }while(x);
16         for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
17     }
18     inline int max(int x,int y){ return x<y?y:x; }
19     inline int min(int x,int y){ return x<y?x:y; }
20     inline void swap(int &x,int &y){ x^=y^=x^=y; }
21     inline void chmax(int &x,int y){ x=x<y?y:x; }
22     inline void chmin(int &x,int y){ x=x<y?x:y; }
23 } using namespace IO;
24 
25 const int NN=2e5+5;
26 int n,q,k,s,t,idx,to[NN<<1],nex[NN<<1],w[NN<<1],head[NN],det[NN][20],mi[20];
27 inline void add(int a,int b,int c){
28     to[++idx]=a; nex[idx]=head[b]; head[b]=idx; w[idx]=c;
29     to[++idx]=b; nex[idx]=head[a]; head[a]=idx; w[idx]=c;
30 }
31 
32 namespace Tree_divide{
33     int cnt,fa[NN],dfn[NN],dep[NN],id[NN],top[NN],siz[NN],son[NN],pre[NN];
34     void dfs1(int s,int f){
35         dep[s]=dep[f]+1; siz[s]=1; fa[s]=f;
36         for(int i=head[s];i;i=nex[i]){
37             int v=to[i];
38             if(v==f) continue;
39             pre[v]=pre[s]+w[i];
40             dfs1(v,s);
41             siz[s]+=siz[v];
42             if(siz[v]>siz[son[s]]) son[s]=v;
43         }
44     }
45     void dfs2(int s,int t){
46         top[s]=t; dfn[s]=++cnt; id[cnt]=s;
47         if(!son[s]) return;
48         dfs2(son[s],t);
49         for(int i=head[s];i;i=nex[i]){
50             int v=to[i];
51             if(v!=fa[s]&&v!=son[s]) dfs2(v,v);
52         }
53     }
54     inline int LCA(int x,int y){
55         while(top[x]!=top[y])
56             if(dep[top[x]]>dep[top[y]]) x=fa[top[x]];
57             else y=fa[top[y]];
58         return dep[x]<dep[y]?x:y;
59     }
60     inline int get(int x){
61         int tmp=pre[x],l,r,res;
62         while(x&&tmp-pre[top[x]]<k) x=fa[top[x]];
63         if(!x) return 0;
64         r=dfn[x]; l=dfn[top[x]];
65         while(l<=r){
66             int mid=l+r>>1;
67             if(tmp-pre[id[mid]]>=k) l=mid+1, res=mid;
68             else r=mid-1;
69         }
70         return id[res];
71     }
72     void dfs3(int s){
73         det[s][0]=get(s);
74         for(int i=1;i<20;i++) det[s][i]=det[det[s][i-1]][i-1];
75         for(int i=head[s];i;i=nex[i])
76             if(to[i]!=fa[s]) dfs3(to[i]);
77     }
78 } using namespace Tree_divide;
79 
80 signed main(){
81     n=read(); k=read(); mi[0]=1;
82     for(int i=1;i<20;i++) mi[i]=mi[i-1]*2;
83     for(int a,b,c,i=1;i<n;i++)
84         a=read(),b=read(),c=read(), add(a,b,c);
85     dfs1(1,0); dfs2(1,1); dfs3(1);
86     q=read();
87     while(q--){
88         s=read(); t=read();
89         int lca=LCA(s,t),ans=0;
90         for(int i=19;~i;i--){
91             if(dep[det[s][i]]>=dep[lca]) s=det[s][i], ans+=mi[i];
92             if(dep[det[t][i]]>=dep[lca]) t=det[t][i], ans+=mi[i];
93         }
94         if(pre[s]+pre[t]-2*pre[lca]>=k) ++ans;
95         write(ans,'\n');
96     }
97     return 0;
98 }
T1

 

上一篇:数据结构学傻了


下一篇:堆-模板