250605 模拟赛
分数:\(100+10+0=110\)
T1 是板子不到一小时直接过了,然后中间干了各种浪费时间的事,最后爆枚举一下 T2 \(n\) 的情况获得了 \(10\) 分的好成绩。
T1
线段树优化建反图,然后发现如果是要求最小值,就先从 \(1\) 号节点开始遍历,能到的节点最小值都是当前节点编号。最大值就从 \(n\) 开始跑。
点击查看代码
#include<bits/stdc++.h>
#define mid ((lf+rt)>>1)
using namespace std;
inline int read()
{
int t=0;char h=getchar();
while(!isdigit(h))h=getchar();
while(isdigit(h))t=(t<<1)+(t<<3)+(h^48),h=getchar();
return t;
}
void write(int x)
{
if(x>9)write(x/10);putchar(x%10+'0');
}
const int N=1e5+10;
int lk[N*4],to[N*200],nxt[N*200],len=1;
inline void insert(int x,int y)
{
to[++len]=y;nxt[len]=lk[x];lk[x]=len;
}
int lc[N*4],rc[N*4],tot=0,pos[N];
void build(int&p,int&q,int lf,int rt)
{
p=++tot;q=++tot;
if(lf==rt)
{
pos[lf]=p;insert(q,p);return;
}
build(lc[p],lc[q],lf,mid);
build(rc[p],rc[q],mid+1,rt);
insert(lc[p],p);insert(rc[p],p);
insert(q,lc[q]);insert(q,rc[q]);
}
void que(int l,int r,int p,int lf,int rt,vector<int>&v)
{
if(l<=lf&&rt<=r)
{
v.push_back(p);return;
}
if(l<=mid)que(l,r,lc[p],lf,mid,v);
if(r>mid)que(l,r,rc[p],mid+1,rt,v);
}
vector<int>u,v;
int rt1,rt2;
int a,b,c,d,n,m;
inline void add(int a,int b,int c,int d)
{
u.clear();v.clear();
que(a,b,rt1,1,n,u);que(c,d,rt2,1,n,v);
for(int x:u)
for(int y:v)insert(x,y);
}
int mn[N*4],mx[N*4];
void dfs(int x,int k,int*vis)
{
vis[x]=k;
for(int i=lk[x],y;i;i=nxt[i])if(!vis[y=to[i]])dfs(y,k,vis);
}
inline void solve()
{
n=read();m=read();
memset(lc,0,n*4*sizeof(int));
memset(rc,0,n*4*sizeof(int));
memset(lk,0,n*4*sizeof(int));
memset(mn,0,n*4*sizeof(int));
memset(mx,0,n*4*sizeof(int));
tot=0;len=1;
build(rt1,rt2,1,n);
for(int i=1;i<=m;i++)
{
a=read();b=read();c=read();d=read();add(c,d,a,b);
}
// for(int i=1;i<=n;i++)cout<<pos[i]<<" ";puts("");
for(int i=1;i<=n;i++)if(!mn[pos[i]])dfs(pos[i],i,mn);
for(int i=n;i>=1;i--)if(!mx[pos[i]])dfs(pos[i],i,mx);
for(int i=1;i<=n;i++)write(mn[pos[i]]),putchar(' '),write(mx[pos[i]]),puts("");
}
int main()
{
freopen("axis.in","r",stdin);
freopen("axis.out","w",stdout);
int t=read();
while(t--)solve();
return 0;
}
T2
考虑一棵树的情况。设树上的叶子节点数为 \(m\),不难发现每个叶子节点至少要连出去一条边,所以说边数至少是 \(\lceil \frac{m}{2} \rceil\)。给每个叶子标号,给叶子 \(i\) 和 \(i+\lceil \frac{m}{2} \rceil\) 连边。但是发现有的节点和它对应的点父亲相同,这些点就向外找一个点连边。
考虑多棵树的情况。发现把所有的树联通的边是一定要有的。所以用连通块个数 \(-1\) 的边把所有的树连起来。发现要让边的数量尽量减少,就要尽量使前面那种情况尽量少出现,所以对于每棵树,把它叶子数量最大的节点的叶子和别的树连边。
连好之后 \(O(m\sqrt m)\) 判断一下是否有三元环就好了。
好的因为我不会判三元环,所以其实是把整张图定向,度数大的指向度数小的点,度数相同边号大的指向边号小的,得到一张 DAG。然后先枚举 \(x\),给 \(x\) 的每个相邻的节点打上标记,再枚举 \(x\) 相邻的点 \(y\),如果 \(y\) 相邻的点中有 \(x\) 的标记,就找到了三元环。可以证明这样的复杂度是 \(O(m\sqrt m)\) 的。