2022.7.1 CF1033E&CF516D
CF1033E
一个 new trick 就是判断二分图先找到一棵生成树,然后判断奇点之间或者偶点之间有无边即可。
我们可以 bfs 地建树,每个点往外拓展使用类似线段树的形式,由于只会拓展 条边,所以此处复杂度是 的。
然后判断,如果是二分图的话直接输出答案了,否则我们类似之前还是用线段树的形式找出一条边就好。
代码比想象中的要冗长,也很难调/ll
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=605;
#define vi vector<int>
#define pb push_back
vi all,q1,q2,qry,G[N],wa;
int n,m,col[N],vis[N];
inline void getall(){
all.clear();
for(int i=1;i<=n;i++)
if(!vis[i])all.pb(i);
}
queue<int>Q;
inline int query(){
if(qry.size()<=1)return 0;
printf("? %d\n",qry.size());
for(auto x:qry)
printf("%d ",x);puts("");
fflush(stdout);
int S=read();return S;
}
inline int Query(){
int S=0,S1=0,S2=0;
qry.clear();
for(auto x:q1)qry.pb(x);
S1=query();qry.clear();
for(auto x:q2)qry.pb(x);
S2=query();
for(auto x:q1)qry.pb(x);
S=query();
return S-S1-S2;
}
inline void Link(int id,int p){
G[id].pb(p);
col[p]=col[id]^1;vis[p]=1;Q.push(p);
}
inline void link(int id,int l,int r){
q1.clear(),q2.clear();
q1.pb(id);
for(int i=l;i<=r;i++)q2.pb(all[i]);
if(!Query())return;
if(l==r)return void(Link(id,all[l]));
int mid=(l+r)>>1;
link(id,l,mid);link(id,mid+1,r);
}
int p1,p2;
inline int loc2(int l,int r,int l2,int r2,int S2){
if(l==r)return l;
int mid=(l+r)>>1;qry.clear();
for(int i=l;i<=mid;i++)qry.pb(wa[i]);
int S1=query();
for(int i=l2;i<=r2;i++)qry.pb(wa[i]);
int S=query();
if(S>S1+S2)return loc2(l,mid,l2,r2,S2);
else return loc2(mid+1,r,l2,r2,S2);
}
inline void loc1(int l,int r,int S){
int mid=(l+r)>>1,S1,S2;
qry.clear();
for(int i=l;i<=mid;i++)qry.pb(wa[i]);
S1=query();qry.clear();
for(int i=mid+1;i<=r;i++)qry.pb(wa[i]);
S2=query();
if(S>S1+S2){
p1=loc2(l,mid,mid+1,r,S2);
p2=loc2(mid+1,r,p1,p1,0);
p1=wa[p1],p2=wa[p2];
}else if(S1)loc1(l,mid,S1);
else loc1(mid+1,r,S2);
}
int dep[N],F[N];
inline void dfs(int x,int fa){
dep[x]=dep[fa]+1;F[x]=fa;
for(auto t:G[x])dfs(t,x);
}
vi R1,R2;
inline void solve(){
for(auto x:qry)wa.pb(x);
int S=query();
loc1(0,wa.size()-1,S);
dfs(1,0);if(dep[p1]<dep[p2])swap(p1,p2);
int t1=p1,t2=p2;
while(dep[p1]>dep[p2])
R1.pb(p1),p1=F[p1];
while(p1!=p2)R1.pb(p1),R2.pb(p2),p1=F[p1],p2=F[p2];
int len=R1.size()+R2.size()+1;
printf("N %d\n",len);
printf("%d ",p1);reverse(R1.begin(),R1.end());
for(auto x:R1)printf("%d ",x);
for(auto x:R2)printf("%d ",x);
fflush(stdout);exit(0);
}
int main(){
n=read();vis[1]=1;
getall();Q.push(1);
while(!Q.empty()&&!all.empty()){
int x=Q.front();Q.pop();
link(x,0,all.size()-1);
getall();
}qry.clear();
for(int i=1;i<=n;i++)if(!col[i])qry.pb(i);
if(query())solve();qry.clear();
for(int i=1;i<=n;i++)if(col[i])qry.pb(i);
if(query())solve();qry.clear();
for(int i=1;i<=n;i++)if(col[i])qry.pb(i);
printf("Y %d\n",qry.size());
for(auto x:qry)printf("%d ",x);puts("");
return 0;
}
CF516D
这种树上最远一看就是直径嘛,我们求出直径即求出所有 值。此时我们把最小的 提为根,形成一个堆,每次询问二分出最远的满足条件的祖先,链加即可。
其实我自己的想法:主席树好像复杂度也是正确的,但是貌似难写亿点点然后常数也有亿点点大。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m,beg[maxn],nex[maxn],to[maxn],w[maxn],e,p1,p2;
inline void add(int x,int y,int z){
e++;nex[e]=beg[x];beg[x]=e;to[e]=y;w[e]=z;
e++;nex[e]=beg[y];beg[y]=e;to[e]=x;w[e]=z;
}
int Mx1[maxn],Mx2[maxn],id1[maxn],id2[maxn],ans;
int dep[maxn],dis[maxn],F[maxn][20],f[maxn],rt;
inline void dfs(int x,int fa){
Mx1[x]=0;id1[x]=x;F[x][0]=fa;
dep[x]=dep[fa]+1;
for(int i=1;i<=19;i++)
F[x][i]=F[F[x][i-1]][i-1];
for(int i=beg[x];i;i=nex[i]){
int t=to[i];
if(t==fa)continue;
dis[t]=dis[x]+w[i];dfs(t,x);
if(Mx1[t]+w[i]>Mx1[x]){
Mx2[x]=Mx1[x];id2[x]=id1[x];
Mx1[x]=Mx1[t]+w[i];id1[x]=id1[t];
}else if(Mx1[t]+w[i]>Mx2[x])
Mx2[x]=Mx1[t]+w[i],id2[x]=id1[t];
}if(Mx1[x]+Mx2[x]>ans)p1=id1[x],p2=id2[x],ans=Mx1[x]+Mx2[x];
}
inline int lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=19;~i;--i)
if(dep[F[x][i]]>=dep[y])x=F[x][i];
if(x==y)return x;
for(int i=19;~i;--i)
if(F[x][i]^F[y][i])x=F[x][i],y=F[y][i];
return F[x][0];
}
inline int Dis(int x,int y){
return dis[x]+dis[y]-2*dis[lca(x,y)];
}
int L,cnt[maxn];
inline void calc(int x,int fa){
int anc=x;
for(int i=19;~i;--i)
if(F[anc][i]&&f[F[anc][i]]+L>=f[x])anc=F[anc][i];
for(int i=beg[x];i;i=nex[i])
if(to[i]^fa)calc(to[i],x),cnt[x]+=cnt[to[i]];
cnt[x]++,cnt[F[anc][0]]--;
}
inline void solve(){
L=read();
memset(cnt,0,sizeof(cnt));
calc(rt,0);int Mx=0;
for(int i=1;i<=n;i++)
Mx=max(Mx,cnt[i]);
printf("%lld\n",Mx);
}
signed main(){
n=read();
for(int i=1,x,y,z;i<n;i++)
x=read(),y=read(),z=read(),add(x,y,z);
dfs(1,0);
for(int i=1;i<=n;i++)
f[i]=max(Dis(i,p1),Dis(i,p2));
for(int i=1;i<=n;i++)
if(!rt||f[i]<f[rt])rt=i;
memset(F,0,sizeof(F));
dfs(rt,0);
m=read();
while(m--)solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下